Caméra All-sky plug-in RICOH THETA J'ai créé un client pour l'API THETA v2.1 qui peut être utilisé pour le développement, je vais donc en présenter le contenu.
Le code source est disponible sur GitHub. https://github.com/theta4j/theta-web-api
Comme le titre l'indique, je l'ai fait pour une utilisation dans le développement de plug-ins RICOH THETA.
RICOH THETA V fonctionne sur un système d'exploitation Android, et vous pouvez librement développer et utiliser des applications en vous inscrivant en tant que développeur. L'application Android développée pour THETA s'appelle un plug-in.
Et le familier API THETA comme l'API THETA est également accessible à partir du plug-in. Puisque le serveur d'API fonctionne dans THETA, accédez-y avec 127.0.0.1
. En d'autres termes, vous pouvez accéder à l'API THETA à partir du plug-in pour filmer et configurer.
Puisque le plug-in est en fait une application Android, le langage de développement est Kotlin ou Java. Cependant, je n'ai pas trouvé la bibliothèque d'API THETA pour Java et le SDK officiel contenait juste un peu d'exemple de code. Peut-être que l'API THETA est une API simple qui échange simplement JSON sur HTTP, il n'y a donc aucune motivation pour implémenter une bibliothèque cliente.
J'ai donc réalisé une implémentation Java du client API THETA.
L'introduction est devenue longue, mais je vais vous montrer comment l'utiliser. L 'Exemple de référentiel est écrit en Java, je vais donc l'écrire en Kotlin ici.
Cette bibliothèque est publiée par MavenCentral et JCenter, donc Gradle peut être installé en ajoutant simplement deux lignes à build.gradle
.
repositories {
...
jcenter() //Ajouter cette ligne
}
dependencies {
...
implementation 'org.theta4j:theta-web-api:1.4.0' //Ajouter cette ligne
}
En gros, créez une instance de la classe ʻorg.theta4j.webapi.Theta` et appelez les méthodes qui s'y développent.
La manière de créer un objet thêta dépend de la manière dont vous vous connectez à THETA.
//Lors de l'utilisation à partir du plug-in THETA
//Le point final est http://127.0.0.1:Devenir 8080
val theta = Theta.createForPlugin()
//THETA est Wi-Dans le cas du mode maître Fi(Mode AP)
//Le point final est http://192.168.1.Devenir 1
val theta = Theta.create()
//THETA Wi-Lorsque Fi est en mode esclave et que l'authentification Digest est désactivée(Mode CL)
//* L'adresse IP varie en fonction de l'environnement
val theta = Theta.create("http://192.168.100.34")
//THETA Wi-Si Fi est en mode esclave et que l'authentification Digest est activée(Mode CL)
//* L'adresse IP varie en fonction de l'environnement
val theta = Theta.create("http://192.168.100.34", "username", "password")
Prendre une image fixe est très simple. Appelez simplement la méthode takePicture
.
theta.takePicture()
Cependant, la commande de prise de vue n'est pas exécutée immédiatement, donc si vous voulez le résultat, procédez comme suit.
//Non terminé de manière synchrone!!
// res.res jusqu'à ce que l'état soit DONE.le résultat est nul
var res = theta.takePicture()
//Interroger à intervalles de 100 ms
while(res.state != CommandState.DONE) {
res = theta.commandStatus(res)
Thread.sleep(100)
}
println(res.result) //L'URL du résultat de la prise de vue s'affiche
Il est utile de définir une fonction d'assistance comme celle-ci:
fun <R> waitForDone(response: CommandResponse<R>): CommandResponse<R> {
var res = response //Puisque l'argument formel est val, redéfinissez la variable de var
while (res.state != CommandState.DONE) {
res = theta.commandStatus(res)
Thread.sleep(100)
}
return res
}
fun main(args : Array<String>) {
val res = waitForDone(theta.takePicture())
println(res.result) //L'URL du résultat de la prise de vue s'affiche
}
Les paramètres d'options et les valeurs de prise en charge peuvent être appelés avec la méthode getOptions
.
Voici un exemple de réglage de la valeur maximale tout en acquérant la valeur de réglage du son de l'obturateur et la valeur de prise en charge en même temps.
val opts = theta.getOptions(SHUTTER_VOLUME, SHUTTER_VOLUME_SUPPORT)
val volume opts.get(SHUTTER_VOLUME)
val support = opts.get(SHUTTER_VOLUME_SUPPORT)
println("Current Volume : $volume")
theta.setOption(SHUTTER_VOLUME, support.maxShutterVolume)
SHUTTER_VOLUME
et SHUTTER_VOLUME_SUPPORT
sont des constantes définies dans la classe ʻorg.theta4j.webapi.Options`.
Pour obtenir et définir une valeur d'option unique, utilisez la méthode getOption
/ setOption
.
val shutterVolume = theta.getOption(SHUTTER_VOLUME)
theta.setOption(SHUTTER_SPEED, ShutterSpeed._1_100)
Lors de la prise de vue d'une image fixe avec la priorité à la vitesse d'obturation et une exposition de 10 secondes, le code est le suivant.
import org.theta4j.webapi.*
import org.theta4j.webapi.Options.*
val theta = Theta.createForPlugin()
fun main(args : Array<String>) {
val opts = OptionSet.Builder()
.put(CAPTURE_MODE, CaptureMode.IMAGE)
.put(EXPOSURE_PROGRAM, ExposureProgram.SHUTTER_SPEED)
.put(SHUTTER_SPEED, ShutterSpeed._10)
.build()
theta.setOptions(opts)
theta.takePicture()
}
Vous pouvez également obtenir la vidéo pour un aperçu en direct. Puisque vous pouvez obtenir une chaîne d'octets JPEG, vous pouvez la décoder avec BitmapFactory
sur Android.
theta.livePreview.use { stream ->
while(true) {
val frame = stream.nextFrame() //Chaîne d'octets JPEG pour une feuille(InputStream)
val bmp = BitmapFactory.decodeStream(frame) //Décoder(Exemple Android)
//Ici, processus de dessin bmp, etc.
}
}
Pour toute autre utilisation, veuillez vous référer à Javadoc ou poser une question dans la section commentaires.
Soyez prudent lorsque vous l'utilisez avec le plug-in Android ou THETA.
Tout d'abord, ajoutez la ligne suivante à ʻAndroidManifest.xml` car vous avez besoin d'autorisations Internet.
<uses-permission android:name="android.permission.INTERNET"/>
De plus, les méthodes avec accès E / S, telles que Theta # takePicture
et Theta # getOptions
, ne peuvent pas être exécutées dans un thread d'interface utilisateur.
override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent) {
//Les événements clés, etc. sont exécutés dans le thread de l'interface utilisateur
theta.takePicture() //Cela entraînera une erreur
}
Utilisez ʻExecutorService` etc. pour l'exécuter dans un autre thread.
private val executor = Executors.newSingleThreadExecutor()
override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent) {
executor.submit {
theta.takePicture() //OK car ce n'est pas un fil d'interface utilisateur
}
}
A partir de là, nous parlerons de design.
Premièrement, nous fixons des objectifs de développement.
Fondamentalement, j'étais conscient de l'avoir largement utilisé à des fins autres que le développement de plug-ins.
Comme mentionné ci-dessus, l'API THETA est essentiellement une API permettant d'échanger JSON sur HTTP. Autrement dit, vous avez besoin d'une bibliothèque HTTP et d'une bibliothèque JSON.
Je pensais que HttpURLConnection
serait suffisant pour HTTP, mais THETA V nécessite une authentification Digest lors de l'exécution en mode client. J'ai trouvé une Looking Digest Authentication Library pour okhttp, j'ai donc décidé d'utiliser okhttp. La documentation est également substantielle et semble bonne.
Je voulais utiliser JSON-B pour JSON, mais cela ne fonctionnait pas sur Android. J'ai décidé d'utiliser GSON au lieu de chasser profondément.
API THETA est [API Open Spherical Camera](https://developers.google.com/streetview/open-spherical- Basé sur camera /) (API OSC), il possède ses propres extensions. Par conséquent, cette fois, le package pour l'API OSC et le package pour l'extension d'origine de THETA sont séparés.
paquet | Aperçu |
---|---|
org.theta4j.osc | Package pour l'API Open Spherical Camera |
org.theta4j.webapi | Package d'extension propriétaire OSC API THETA |
Cependant, nous avons décidé de minimiser le paquet ʻorg.theta4j.osc et d'implémenter toutes les fonctionnalités que les fournisseurs tiers sont autorisés à étendre dans ʻorg.theta4j.webapi
.
Par exemple, caemra.startCapture
est une commande définie dans l'API OSC, mais l'API THETA ajoute un paramètre d'extension appelé _mode
. Par conséquent, définissez-le dans le package webapi
.
D'autre part, la commande camera.takePicture
est également une commande définie par l'API OSC, mais il n'y a pas de spécification étendue dans l'API THETA. Par conséquent, camera.takeCapture
pourrait être défini dans le paquet ʻosc`.
Cependant, il est déroutant d'avoir des packages différents en fonction de la présence ou de l'absence d'extensions, et ce n'est pas toujours le cas que les extensions ne seront pas incluses dans le futur, j'ai donc décidé de définir toutes les fonctions qui peuvent être étendues dans le package webapi
.
L'API OSC a une fonction optionnelle de réglage / acquisition. Il définit / récupère des valeurs d'option avec différents types à la fois.
Par exemple, si vous souhaitez définir l'alimentation Bluetooth et la vitesse d'obturation en même temps, envoyez le JSON suivant. Dans cet exemple, String et Number sont mélangés.
{
"options": {
"_bluetoothPower": "ON",
"shutterSpeed": 0.01
}
}
Il s'agit d'une combinaison d'une clé de type java.lang.String
et d'une valeur de n'importe quel type, donc en Java ce serait Map <String, Object>
. Cependant, si le type de valeur est java.lang.Object
, la conversion descendante est requise lors de la récupération de la valeur, ce qui la rend sûre du tout.
Par conséquent, j'ai défini la classe suivante qui contient un ensemble de valeurs d'options. Si vous spécifiez un objet Class approprié pour l'argument type
, une erreur de compilation se produira s'il y a une différence entre les types de type
et de valeur
, et vous pouvez trouver le problème au moment de la compilation. C'est le modèle introduit dans Effective Java 2nd Edition en tant que «Conteneurs hétérogènes de type sûr».
public final class OptionSet {
public <T> void put(Class<T> type, String name, T value);
public <T> T get(Class<T> type, String name);
}
public static void main(String[] args) {
OptionSet opts = ...;
opts.put(BigDecimal.class, "shutterSpeed", "foo") //Erreur de compilation due à une incompatibilité de type
}
Cependant, la combinaison de «type» et «nom» est constante. Par exemple, le type de shutterSpeed
est toujours Number, jamais String ou Boolean.
Par conséquent, en réalité, le type «Option
public interface Option<T> {
Class<T> getType();
String getName();
}
public final class Options {
public static final Option<BigDecimal> SHUTTER_SPEED = OptionImpl.create("shutterSpeed", BigDecimal.class)
}
public final class OptionSet {
public <T> void put(Option<T> option, T value);
...
}
public static void main(String[] args) {
OptionSet opts = ...;
opts.put(Options.SHUTTER_SPEED, "foo") //Erreur de compilation due à une incompatibilité de type
}
La fonction d'exécution de commande est également conçue pour être de type sécurisé en utilisant le modèle de «conteneurs hétérogènes de type sécurisé».
Nous avons brièvement présenté l'utilisation et la conception de l'implémentation client de l'API THETA. Nous espérons que cela aidera ceux qui souhaitent développer des applications et des plug-ins utilisant l'API THETA.
RICOH THETA Plugins est facile à développer. Surtout si vous connaissez les applications Android, vous pouvez les développer immédiatement, alors essayez-le.
L'article suivant résume brièvement comment démarrer avec le développement de plug-ins.
[Développement du plug-in THETA] Comment exécuter le SDK du plug-in RICOH THETA avec THETA
Recommended Posts