Capturar una imagen
Módulo de ejemplo: helloindicapture.
giveMeAnImage(): la visualización sin ningún código
HelloIndiCapture::HelloIndiCapture(...)
: IndiModule(...)
{
giveMeADevice("camera", "Camera", INDI::BaseDevice::CCD_INTERFACE);
giveMeAnImage();
}giveMeAnImage() construye por sí sola las propiedades image (solo lectura, elemento ElementImg) e imgparms (modo de stretch, calidad jpeg) — nada que declarar en JSON para esto. Lo que el módulo todavía debe proporcionar es la captura en sí misma y la devolución de la imagen una vez recibida.
Solicitar la captura
void HelloIndiCapture::onExternalEvent(OST::ExtEvent event)
{
if (event.ev != OST::ExtEvType::SV || event.prpkey != "actions" || event.eltkey != "capture") return;
requestCapture(getString("devices", "camera"),
getFloat("shot", "exposure"),
getFloat("shot", "gain"),
getFloat("shot", "offset"));
getEltBool("actions", "capture")->setValue(false, true);
}requestCapture(device, exposición, gain, offset) envía la solicitud al device; shot y actions son dos propiedades clásicas declaradas en JSON (ver El módulo más pequeño), nada específico de INDI en su declaración. requestCapture() ya activa por sí misma la recepción de BLOBs en ese device (setBLOBMode(B_ALSO, ...)) — no es necesario llamarlo uno mismo antes.
Recibir el BLOB
void HelloIndiCapture::updateProperty(INDI::Property property)
{
IndiModule::updateProperty(property);
if (QString(property.getDeviceName()) == getString("devices", "camera") && property.getType() == INDI_BLOB)
{
newBLOB(property);
}
}
void HelloIndiCapture::newBLOB(INDI::PropertyBlob pblob)
{
loadImageFromBlob(pblob, 64, [this]() { refreshPreview(); });
}Capturar una imagen es el único caso, en esta serie de ejemplos, que sobrecarga updateProperty() (protegido) en lugar de onUpdateProperty() (público) — ver la vista de conjunto. El encadenamiento IndiModule::updateProperty(property) en la primera línea no es opcional: es él quien mantiene actualizada la lista de valores de devices.* en una conexión. Olvidarlo rompe ese refresco silenciosamente, sin error visible.
Un módulo que controla una cámara y un focuser no tiene que elegir entre los dos mecanismos: IndiModule::updateProperty(property) llama él mismo a onUpdateProperty(property) a la salida, para cualquier propiedad, no solo las del device que motivó la sobrecarga. Sobrecargar updateProperty() para interceptar los BLOBs de la cámara (como arriba) y sobrecargar onUpdateProperty() para seguir la posición del focuser (como helloindiwrite) coexisten, por tanto, sin conflicto en el mismo módulo, siempre que el encadenamiento anterior esté bien hecho.
En las versiones recientes de libindi, un BLOB llega como cualquier otra propiedad a través de updateProperty(), tipada INDI_BLOB — ya no hay un callback dedicado que sobrecargar. newBLOB() arriba es un método privado ordinario del módulo, no una sobrecarga; el despacho manual (property.getType() == INDI_BLOB) es el único medio actual de dispararla, exactamente como hace dummy.cpp en el código del core. Simplificar esto para que un módulo ya no necesite sobrecargar updateProperty() él mismo se menciona en el issue ost/ostserver#271, aún no decidido.
Republicar la imagen
void HelloIndiCapture::refreshPreview()
{
if (!_image) return;
QImage rawImage = _image->getRawQImage();
atomicSaveJpeg(rawImage, getWebroot() + "/" + getModuleName() + ".jpeg");
OST::ImgData data = _image->ImgStats();
data.mUrlJpeg = getModuleName() + ".jpeg";
getEltImg("image", "image")->setValue(data, true);
}loadImageFromBlob() llena _image (la trama residente del módulo, una sola a la vez) y ya aplica el stretch actual; refreshPreview() solo tiene que guardar un jpeg en el webroot y empujar su URL en el elemento image. refreshPreview() también es llamada automáticamente por el framework cada vez que el usuario cambia imgparms.stretch — un módulo que lo necesite solo escribe este método una vez.
ImgStats() solo llena los campos de OST::ImgData que se calculan directamente a partir de los píxeles brutos: min/max/mean/stddev/median por canal, histogram, dimensiones. Los campos HFRavg, HFRavgDev y starsCount existen efectivamente en la estructura, pero ImgStats() los deja en cero.
Todo análisis de imagen más avanzado (detección de estrellas, HFR, plate solving…) es un asunto de negocio, propio de cada módulo, que no entra en el alcance de este framework — no es el papel de esta documentación cubrirlo. Para inspirarse en una implementación real, ver por ejemplo el módulo Focus del core (src/modules/focus/focus.cpp), que gestiona esto mediante su propia instancia de la clase Solver (libs/solver.cpp).