Estou trabalhando com dm-script para processar um perfil bruto. Primeiro calculo sua primeira derivada para detectar bordas e, então, deixo os usuários selecionarem uma região entre essas bordas no gráfico de derivadas. No entanto, gostaria que a mesma caixa de seleção também aparecesse simultaneamente no gráfico de perfil bruto original para guiar o usuário intuitivamente.
Atualmente, minha implementação usa funções compostas para empilhar verticalmente dois gráficos (perfil bruto e perfil derivado). Embora funcione, a sincronização entre regiões interativas parece incômoda e não muito elegante.
Existe uma maneira melhor ou mais eficiente no script DM para vincular regiões de seleção interativas entre o perfil original e seu gráfico derivado?
Quaisquer sugestões ou exemplos de código são bem-vindos!
Class CMyHandleLegend
{
TagGroup CreateLegendTags(object self, CompoundDocument doc, number selectedCMDid)
{
TagGroup Legend = NewTagList();
for(number i = 0; i < doc.CompoundDocumentCountImageDisplays() - 1; i++)
{
ImageDisplay ithDisp = doc.CompoundDocumentGetImageDisplay(i);
string buttonName = ithDisp.ImageDisplayGetImage().ImageGetName();
number buttonCMDid = 10000 + ithDisp.ComponentGetCompoundID();
TagGroup button = NewTagGroup();
button.TagGroupSetTagAsUInt32("ID", buttonCMDid);
button.TagGroupSetTagAsString("Name", buttonName);
button.TagGroupSetTagAsBoolean("Selected", buttonCMDid == selectedCMDid);
Legend.TagGroupAddTagGroupAtEnd(button);
}
// Legend.TagGroupOpenBrowserWindow(0)
return Legend;
}
void GetIthDisplayInfo(object self, CompoundDocument doc, number i, number &compID, number &AR, string &name)
{
ImageDisplay ithDisp = doc.CompoundDocumentGetImageDisplay(i);
Image ithImg = ithDisp.ImageDisplayGetImage();
compID = ithDisp.ComponentGetCompoundID();
Result("\n" + compID)
number sx = ithImg.ImageGetDimensionSize(0);
number sy = ithImg.ImageGetDimensionSize(1);
AR = (0 < sy) ? sx / sy : 1;
AR = clip(AR, 0.5, 2);
name = ithImg.ImageGetName();
}
TagGroup CreateRowLayout(object self, CompoundDocument doc, number cmdID)
{
number rowH = 300;
TagGroup Layout = CreateCompoundDocumentLayoutTagGroup("CompoundDocument Example 2");
TagGroup row = Layout.CompoundDocumentLayoutAddRow(rowH);
TagGroup row2 = Layout.CompoundDocumentLayoutAddRow(rowH);
number iCompID, iAR;
string iName;
number nImgD = doc.CompoundDocumentCountImageDisplays();
for(number i = 0; i < nImgD; i++)
{
self.GetIthDisplayInfo(doc, i, iCompID, iAR, iName);
if ((iCompID + 10000) == cmdID)
row.CompoundDocumentLayoutAddColumnAsImage(rowH * iAR, iName, iCompID);
if ((iCompID + 10000) == (cmdID + 1))
row2.CompoundDocumentLayoutAddColumnAsImage(rowH * iAR, iName, iCompID);
}
Layout.TagGroupSetTagAsBoolean("Legend", 1);
Layout.TagGroupSetTagAsTagGroup("Buttons", self.CreateLegendTags(doc, cmdID));
return Layout;
}
void ChooseLayout(object self, CompoundDocument doc, number cmdID)
{
TagGroup Layout = self.CreateRowLayout(doc, cmdID);
//Layout.TagGroupOpenBrowserWindow(0);
doc.CompoundDocumentShow(Layout);
}
void HandleLegendButtonPressed(object self, number flags, CompoundDocument doc, number cmdID)
{
Result("\n Received button message from: " + doc.ImageDocumentGetName());
Result("\n Button ID: " + cmdID);
self.ChooseLayout(doc, cmdID);
}
}
Image absolute_first_derivative(Image in)
{
// Edge detected at the peak (maximum absolute value) of the first derivative curve
Number size_x, size_y, origin, scale
String units
Image out
in.ImageGetDimensionCalibration(0, origin, scale, units, 0)
in.GetSize(size_x, size_y)
if (size_y != 1) Result("Only compatible with 1D image")
out := RealImage("first_derivative", 4, size_x, size_y)
out = abs(in[icol + 1, irow] - in[icol, irow])
//out[0, 0] = 0
//out[size_x - 1, 0] = 0
out.ImageSetDimensionCalibration(0, origin, scale, units, 0)
return out
}
void ShowLegendCompoundDocument()
{
CompoundDocument doc = NewCompoundDocument("CompoundDoc Example");
image img1 := RealImage("test", 4, 200);
img1 = 100
img1[0,0,1,50] = 50
img1[0,150,1,200] = 50
Image img2 := absolute_first_derivative(img1)
Image img3 = img1
Image img4 := absolute_first_derivative(img3)
img1.SetName("test 1")
img2.SetName("test 2")
img3.SetName("test 3")
img4.SetName("test 4")
doc.ImageDocumentAddImageDisplay(img1.ImageCreateImageDisplay(-2));
doc.ImageDocumentAddImageDisplay(img2.ImageCreateImageDisplay(-2));
doc.ImageDocumentAddImageDisplay(img3.ImageCreateImageDisplay(-2));
doc.ImageDocumentAddImageDisplay(img4.ImageCreateImageDisplay(-2));
object obj = Alloc(CMyHandleLegend);
number listenID = doc.CompoundDocumentAddListener(obj, "compounddocument_buttonpressed:HandleLegendButtonPressed");
obj.ChooseLayout(doc, 10008);
}
ShowLegendCompoundDocument();
No script DM, o que você está chamando de "caixa de seleção" é um objeto ROI em um objeto LinePlotImageDisplay. Há várias maneiras de ser notificado de que um ROI mudou e usar isso para manter vários ROIs sincronizados. Isso geralmente é feito por meio de uma construção chamada Listener. Faça uma pesquisa sobre "[dm-script] listener" para ver várias postagens anteriores que abordam esse tópico.
No seu caso, acredito que o seguinte pode ser particularmente útil:
Pergunta sobre notificação de alteração de ROI