All-Sky-Kamera RICOH THETA-Plug-In Ich habe einen Client für THETA API v2.1 erstellt, der für die Entwicklung verwendet werden kann, daher werde ich den Inhalt vorstellen.
Der Quellcode ist auf GitHub verfügbar. https://github.com/theta4j/theta-web-api
Wie der Titel schon sagt, habe ich es für die Entwicklung von RICOH THETA-Steckern entwickelt.
RICOH THETA V läuft auf einem Android-basierten Betriebssystem, und Sie können Apps frei entwickeln und verwenden, indem Sie sich als Entwickler registrieren. Die für THETA entwickelte Android-App wird als Plug-In bezeichnet.
Auf die bekannte THETA-API als THETA-API kann auch über das Plug-In zugegriffen werden. Da der API-Server in THETA ausgeführt wird, greifen Sie mit 127.0.0.1
darauf zu. Mit anderen Worten, Sie können über das Plug-In auf die THETA-API zugreifen, um zu fotografieren und zu konfigurieren.
Da das Plug-In eigentlich eine Android-App ist, ist die Entwicklungssprache Kotlin oder Java. Ich konnte jedoch die THETA-API-Bibliothek für Java nicht finden, und das offizielle SDK enthielt nur ein wenig Beispielcode. Möglicherweise ist die THETA-API eine einfache API, die nur JSON über HTTP austauscht, sodass keine Motivation besteht, eine Clientbibliothek zu implementieren.
Also habe ich eine Java-Implementierung des THETA API-Clients gemacht.
Die Einführung ist lang geworden, aber ich werde Ihnen zeigen, wie man sie benutzt. Das Repository-Beispiel ist in Java geschrieben, daher werde ich es hier in Kotlin schreiben.
Diese Bibliothek wird von MavenCentral und JCenter veröffentlicht, sodass Gradle installiert werden kann, indem nur zwei Zeilen zu "build.gradle" hinzugefügt werden.
repositories {
...
jcenter() //Fügen Sie diese Zeile hinzu
}
dependencies {
...
implementation 'org.theta4j:theta-web-api:1.4.0' //Fügen Sie diese Zeile hinzu
}
Erstellen Sie grundsätzlich eine Instanz der Klasse "org.theta4j.webapi.Theta" und rufen Sie die dort wachsenden Methoden auf, um sie zu verwenden.
Wie Sie ein Theta-Objekt erstellen, hängt davon ab, wie Sie eine Verbindung zu THETA herstellen.
//Bei Verwendung über das THETA-Plug-In
//Der Endpunkt ist http://127.0.0.1:Werden Sie 8080
val theta = Theta.createForPlugin()
//THETA ist Wi-Im Falle des Fi-Master-Modus(AP-Modus)
//Der Endpunkt ist http://192.168.1.Werden Sie 1
val theta = Theta.create()
//THETA Wi-Wenn sich Fi im Slave-Modus befindet und die Digest-Authentifizierung deaktiviert ist(CL-Modus)
//* Die IP-Adresse variiert je nach Umgebung
val theta = Theta.create("http://192.168.100.34")
//THETA Wi-Wenn sich Fi im Slave-Modus befindet und die Digest-Authentifizierung aktiviert ist(CL-Modus)
//* Die IP-Adresse variiert je nach Umgebung
val theta = Theta.create("http://192.168.100.34", "username", "password")
Das Aufnehmen eines Standbilds ist sehr einfach. Rufen Sie einfach die Methode takePicture
auf.
theta.takePicture()
Der Aufnahmebefehl wird jedoch nicht sofort ausgeführt. Wenn Sie also das Ergebnis erzielen möchten, gehen Sie wie folgt vor.
//Nicht synchron abgeschlossen!!
// res.res bis der Status FERTIG ist.Ergebnis ist null
var res = theta.takePicture()
//Abfrage in Intervallen von 100 ms
while(res.state != CommandState.DONE) {
res = theta.commandStatus(res)
Thread.sleep(100)
}
println(res.result) //Die URL des Aufnahmeergebnisses wird angezeigt
Es ist nützlich, eine Hilfsfunktion wie folgt zu definieren:
fun <R> waitForDone(response: CommandResponse<R>): CommandResponse<R> {
var res = response //Da das formale Argument val ist, definieren Sie die Variable var neu
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) //Die URL des Aufnahmeergebnisses wird angezeigt
}
Optionseinstellungen und Unterstützungswerte können mit der Methode "getOptions" aufgerufen werden.
Im Folgenden finden Sie ein Beispiel für die Einstellung des Maximalwerts bei gleichzeitiger Erfassung des Verschlussgeräusch-Einstellwerts und des Unterstützungswerts.
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
und SHUTTER_VOLUME_SUPPORT
sind Konstanten, die in der Klasse org.theta4j.webapi.Options
definiert sind.
Verwenden Sie die Methode "getOption" / "setOption", um einen einzelnen Optionswert abzurufen und festzulegen.
val shutterVolume = theta.getOption(SHUTTER_VOLUME)
theta.setOption(SHUTTER_SPEED, ShutterSpeed._1_100)
Bei der Aufnahme eines Standbilds mit Verschlusszeitpriorität und Belichtung von 10 Sekunden lautet der Code wie folgt.
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()
}
Sie können das Video auch für die Live-Vorschau erhalten. Da Sie eine JPEG-Byte-Zeichenfolge erhalten können, können Sie diese mit BitmapFactory
unter Android dekodieren.
theta.livePreview.use { stream ->
while(true) {
val frame = stream.nextFrame() //JPEG-Byte-Zeichenfolge für ein Blatt(InputStream)
val bmp = BitmapFactory.decodeStream(frame) //Dekodieren(Android Beispiel)
//Hier bmp Zeichenprozess usw.
}
}
Weitere Informationen finden Sie unter Javadoc oder stellen Sie im Kommentarbereich eine Frage.
Seien Sie vorsichtig, wenn Sie es mit dem Android- oder THETA-Plug-In verwenden.
Fügen Sie zunächst die folgende Zeile zu "AndroidManifest.xml" hinzu, da Sie Internetberechtigungen benötigen.
<uses-permission android:name="android.permission.INTERNET"/>
Außerdem können Methoden mit E / A-Zugriff wie "Theta # takePicture" und "Theta # getOptions" nicht in einem UI-Thread ausgeführt werden.
override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent) {
//Schlüsselereignisse usw. werden im UI-Thread ausgeführt
theta.takePicture() //Dies führt zu einem Fehler
}
Verwenden Sie "ExecutorService" usw., um es in einem anderen Thread auszuführen.
private val executor = Executors.newSingleThreadExecutor()
override fun onKeyDown(keyCode: Int, keyEvent: KeyEvent) {
executor.submit {
theta.takePicture() //OK, da es sich nicht um einen UI-Thread handelt
}
}
Von hier an werden wir über Design sprechen.
Zunächst setzen wir uns einige Entwicklungsziele.
Grundsätzlich war ich mir bewusst, dass es für andere Zwecke als die Plug-In-Entwicklung weit verbreitet ist.
Wie oben erwähnt, ist die THETA-API im Grunde eine API zum Austausch von JSON über HTTP. Das heißt, Sie benötigen eine HTTP-Bibliothek und eine JSON-Bibliothek.
Ich dachte, dass "HttpURLConnection" für HTTP ausreichen würde, aber THETA V erfordert eine Digest-Authentifizierung, wenn es im Client-Modus ausgeführt wird. Ich habe eine Looking Digest Authentication Library für okhttp gefunden und mich daher für okhttp entschieden. Die Dokumentation ist auch umfangreich und sieht gut aus.
Ich wollte JSON-B für JSON verwenden, aber es funktionierte nicht unter Android. Ich habe mich entschieden, GSON zu verwenden, anstatt tief zu jagen.
THETA API ist [Open Spherical Camera API](https://developers.google.com/streetview/open-spherical- Basierend auf camera /) (OSC API) verfügt es über eigene Erweiterungen. Daher werden dieses Mal das Paket für die OSC-API und das Paket für die ursprüngliche Erweiterung von THETA getrennt.
Paket | Überblick |
---|---|
org.theta4j.osc | Paket für Open Spherical Camera API |
org.theta4j.webapi | OSC API THETA proprietäres Erweiterungspaket |
Wir haben uns jedoch entschlossen, das Paket "org.theta4j.osc" zu minimieren und alle Funktionen zu implementieren, die Drittanbieter in "org.theta4j.webapi" erweitern dürfen.
Beispielsweise ist "caemra.startCapture" ein Befehl, der in der OSC-API definiert ist, aber die THETA-API fügt einen Erweiterungsparameter mit dem Namen "_mode" hinzu. Definieren Sie es daher im webapi
-Paket.
Andererseits ist der Befehl camera.takePicture
auch ein Befehl, der von der OSC-API definiert wird, aber es gibt keine erweiterte Spezifikation in der THETA-API. Daher könnte "camera.takeCapture" im "osc" -Paket definiert werden.
Es ist jedoch verwirrend, je nach Vorhandensein oder Fehlen von Erweiterungen unterschiedliche Pakete zu haben, und es ist nicht immer so, dass Erweiterungen in Zukunft nicht mehr enthalten sein werden. Daher habe ich beschlossen, alle Funktionen zu definieren, die im webapi
-Paket erweitert werden dürfen.
Die OSC-API verfügt optional über eine Einstell- / Erfassungsfunktion. Es setzt / ruft Optionswerte mit verschiedenen Typen gleichzeitig ab.
Wenn Sie beispielsweise das Bluetooth-Netzteil und die Verschlusszeit gleichzeitig einstellen möchten, senden Sie den folgenden JSON. In diesem Beispiel werden String und Number gemischt.
{
"options": {
"_bluetoothPower": "ON",
"shutterSpeed": 0.01
}
}
Dies ist eine Kombination aus einem Schlüssel vom Typ "java.lang.String" und einem Wert eines beliebigen Typs. In Java wäre dies also "Map <String, Object>". Wenn der Werttyp jedoch "java.lang.Object" ist, ist beim Abrufen des Werts ein Downcasting erforderlich, wodurch er überhaupt typsicher ist.
Daher habe ich die folgende Klasse definiert, die eine Reihe von Optionswerten enthält. Wenn Sie ein geeignetes Klassenobjekt für das Argument "Typ" angeben, tritt ein Kompilierungsfehler auf, wenn zwischen den Typen "Typ" und "Wert" eine Diskrepanz besteht und Sie das Problem beim Kompilieren finden. Dies ist das Muster, das in Effective Java 2nd Edition als "typsichere heterogene Container" eingeführt wurde.
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") //Kompilierungsfehler aufgrund von Typinkongruenz
}
Die Kombination von "Typ" und "Name" ist jedoch konstant. Zum Beispiel ist der Typ von "shutterSpeed" immer "Number", niemals "String" oder "Boolean".
Daher werden in der Realität die folgenden "Typ" und "Name" kombiniert, um den Typ "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") //Kompilierungsfehler aufgrund von Typinkongruenz
}
Die Befehlsausführungsfunktion ist auch typsicher nach dem Muster "typsicherer heterogener Container".
Wir haben kurz die Verwendung und das Design der Client-Implementierung der THETA-API vorgestellt. Wir hoffen, es hilft denen, die Apps und Plug-Ins entwickeln möchten, die die THETA-API verwenden.
RICOH THETA Plugins ist einfach zu entwickeln. Insbesondere wenn Sie Kenntnisse über Android-Apps haben, können Sie diese sofort entwickeln. Probieren Sie es also aus.
Der folgende Artikel fasst kurz zusammen, wie Sie mit der Plug-Entwicklung beginnen.
[THETA-Plug-In-Entwicklung] Ausführen des RICOH THETA-Plug-In-SDK mit THETA
Recommended Posts