Catturare un'immagine
Modulo di esempio: helloindicapture.
giveMeAnImage(): la visualizzazione senza alcun codice
HelloIndiCapture::HelloIndiCapture(...)
: IndiModule(...)
{
giveMeADevice("camera", "Camera", INDI::BaseDevice::CCD_INTERFACE);
giveMeAnImage();
}giveMeAnImage() costruisce da sola le proprietà image (sola lettura, elemento ElementImg) e imgparms (modalità di stretch, qualità jpeg) — nulla da dichiarare in JSON per questo. Ciò che il modulo deve ancora fornire è la capture stessa e il rinvio dell’immagine una volta ricevuta.
Richiedere la capture
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, esposizione, gain, offset) invia la richiesta al device; shot e actions sono due proprietà classiche dichiarate in JSON (vedi Il modulo più piccolo), nulla di specifico a INDI nella loro dichiarazione. requestCapture() attiva già da sola la ricezione dei BLOB su questo device (setBLOBMode(B_ALSO, ...)) — inutile chiamarla da soli prima.
Ricevere il 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(); });
}Catturare un’immagine è l’unico caso, in questa serie di esempi, che sovrascrive updateProperty() (protetto) piuttosto che onUpdateProperty() (pubblico) — vedi la panoramica. Il concatenamento IndiModule::updateProperty(property) sulla prima riga non è opzionale: è ciò che mantiene aggiornata la lista di valori di devices.* su una connessione. Dimenticarlo rompe questo aggiornamento silenziosamente, senza errore visibile.
Un modulo che pilota una camera e un focuser non deve scegliere tra i due meccanismi: IndiModule::updateProperty(property) chiama da sola onUpdateProperty(property) in uscita, per qualsiasi proprietà, non solo quelle del device che ha motivato la sovrascrittura. Sovrascrivere updateProperty() per intercettare i BLOB della camera (come sopra) e sovrascrivere onUpdateProperty() per seguire la posizione del focuser (come helloindiwrite) coesistono quindi senza conflitto nello stesso modulo, a patto che il concatenamento sopra sia fatto correttamente.
Sulle versioni recenti di libindi, un BLOB arriva come qualsiasi altra proprietà tramite updateProperty(), tipizzata INDI_BLOB — non c’è più un callback dedicato da sovrascrivere. newBLOB() sopra è un metodo privato ordinario del modulo, non una sovrascrittura; il dispatch manuale (property.getType() == INDI_BLOB) è l’unico modo attuale per attivarla, esattamente come fa dummy.cpp nel codice del core. Semplificare questo perché un modulo non debba più sovrascrivere updateProperty() da solo è evocato nell’issue ost/ostserver#271, non ancora deciso.
Ripubblicare l’immagine
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() riempie _image (il frame residente del modulo, uno solo alla volta) e applica già lo stretch corrente; refreshPreview() non deve più fare altro che salvare un jpeg nel webroot e spingere il suo URL nell’elemento image. refreshPreview() viene anche richiamata automaticamente dal framework ogni volta che l’utente cambia imgparms.stretch — un modulo che ne ha bisogno scrive questo metodo solo una volta.
ImgStats() riempie solo i campi di OST::ImgData che si calcolano direttamente dai pixel grezzi: min/max/mean/stddev/median per canale, histogram, dimensioni. I campi HFRavg, HFRavgDev e starsCount esistono bene nella struttura, ma ImgStats() li lascia a zero.
Qualsiasi analisi d’immagine più avanzata (rilevamento di stelle, HFR, plate solving…) è un argomento di business, proprio a ciascun modulo, che non entra nel perimetro di questo framework — non è compito di questa documentazione coprirlo. Per ispirarsi a un’implementazione reale, vedi per esempio il modulo Focus del core (src/modules/focus/focus.cpp), che gestisce ciò tramite la propria istanza della classe Solver (libs/solver.cpp).