OpenCV-Bilddarstellung auf Zeichenebene im Dialogfenster

jower

Mitglied
Hallo,
ich habe folgendes Problem und hoffe mal, dass einer von Euch mir weiterhelfen kann.

ich möchte ein IplImage (das ist die OpenCV-Bildklasse) unter MFC anzeigen. Genauergesagt will ich, dass das Bild in nur einem Teil eines Dialogs dargestellt wird. Dazu habe ich einmal das Bild m_image und einmal m_imgCtrl als Handle für meine Zeichenebene, um MFC mitzuteilen, wo ich das Bild hinhaben will.

Die Zeichenebene ist eine Resource mit IDC_IMAGE als ID. mein Plan war über
m_imgCtrl.SetDlgCtrlID(IDC_IMAGE);
bzw. über
DDX_Control(pDX, IDC_IMAGE, m_imgCtrl);
die Zuweisung zu machen, nur wird dann das Bild nicht in der Zeichenebene ausgegeben sondern als Hintegrund im Dialogfenster.

Mein Problem scheint also darin zu bestehen, dass die Zuweisung nicht klappt. kann mir da jemand helfen?
Gruß Jower

Code:
class-CMyView:

IplImage *m_image;
CWnd	m_imgCtrl;



Code:
void CMyView::DoDataExchange(CDataExchange* pDX)
{
	DDX_Control(pDX, IDC_IMAGE, m_imgCtrl);
}

void CMyView::OnDraw(CDC* /*pDC*/)
{
	CMyDoc* pDoc = GetDocument();

	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	m_imgCtrl.SetDlgCtrlID(IDC_IMAGE);

	CDC *pDC = m_imgCtrl.GetDC();
	CvvImage m_CvvImage;
	RECT rect;
	m_imgCtrl.GetWindowRect(&rect);
	m_image = cvLoadImage( "./test.png", 0);

	m_CvvImage.CopyOf( m_image, 1); 
	m_CvvImage.DrawToHDC( pDC->m_hDC, &rect);

	UpdateData();
}
 
Hallo,

so ganz klar ist mit dein Vorhaben nicht geworden. Als "Hintergrund des Dialog" ist dein CMyView und gemeint und als Zeichenebene das Fenster "m_imgCtrl", das kleiner als CView und irgendwo darin platziert wurde?

Die Geschichten mit "SetDlgCtrlID(IDC_IMAGE)" bzw. "DDX_Control(pDX, IDC_IMAGE, m_imgCtrl)" bringen dir eigentlich gar nichts. Dahinter steckt ein ganz anderes Konzept, dass mit deinen Zeichenroutinen in keiner Weise korrespondiert.

Der Code in der OnDraw-Routine schaut so schlecht nicht aus. Das Problem scheint eher beim "m_imgCtrl" zu liegen. Wie hast du das Fenster denn erzeugt und auf dem View plaziert?
Warum zeichnest du denn nicht gleich direkt auf der CView in dem gewünschten Bereich (wie gesagt, ich steige bei deinem Vorhaben nicht ganz durch)?

Grüße
MCoder
 
Hallo MCoder,

Hast recht, vielleicht muß ich noch ein wenig mehr dazu schreiben;)
ich habe ein Fenster (FormView). Über dieses Fenster werden Parameter für die Funktion des Programms übergeben. Das Programm soll ein Bild verarbeiten und das Ergebnisbild im selben Fenster darstellen.
Ich habe also ein Fenster und möchte in einem Teilbereich davon das Ergbnisbild anzeigen.
ich dachte, dazu müßte ich eine Zeichenebene haben. da habe ich wohl zu umständlich gedacht.

Du hast recht, SetDlgCtrlID(IDC_IMAGE) bringt nichts.
Ohne "DDX_Control(pDX, IDC_IMAGE, m_imgCtrl)" funktioniert es aber nicht, liegt wohl daran, dass das Fenster von FormView abgeleitet ist, bzw. irgendwie als Dlg arbeitet. Würde mich schon interessieren.
Auf jeden Fall habe ich´s mittlerweile hingekriegt. Hier der Code:

Code:
class CMyView: public CFormView
{
	IplImage *m_image;
        CWnd	m_imgCtrl;
}

Code:
void CMyView::DoDataExchange(CDataExchange* pDX)
{
	DDX_Control(pDX, IDC_IMAGE, m_imgCtrl);
}

void CMyView::OnDraw(CDC* pDC)
{
	CVisualServoDoc* pDoc = GetDocument();

	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	pDC = m_imgCtrl.GetDC();
	CvvImage m_CvvImage;
	RECT rect;
	m_imgCtrl.GetClientRect(&rect);
	m_image = cvLoadImage( "./test.png", 0);
	m_CvvImage.CopyOf( m_image, 1);
	m_CvvImage.DrawToHDC( pDC->m_hDC, &rect);

	UpdateData();
}

Gruß Jower
 
Hallo Jower,

ich glaube, langsam begreife ich was du meinst. Irgendwo auf deinem FormView gibt es dann vermutlich noch ein Static-Objekt mit der ID "IDC_IMAGE"? Dann brauchst du natürlich "DDX-Control()" um es mit "m_imgCtrl" zu verknüpfen.
Es ist nicht günstig, dass du den übergebenen Zeiger "pDC" mit einem anderen Zeiger (geholt via "GetDC()") überschreibst. Auf jeden Fall solltest du den am Ende mit "ReleaseDC()" wieder freigeben.

Ansonsten würde ich das (unter der Annahme IDC_IMAGE existiert als Control auf dem View) vielleicht so lösen:

Code:
void CMyView::OnDraw(CDC* pDC)
{
    CVisualServoDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);
    if (!pDoc) return;

    CRect rect;
    GetDlgItem(IDC_IMAGE)->GetWindowRect(&rect);
    ScreenToClient(&rect);
    
    m_image = cvLoadImage( "./test.png", 0);
    m_CvvImage.CopyOf( m_image, 1);
    m_CvvImage.DrawToHDC( pDC->m_hDC, &rect);
}

Gruß
MCoder
 
Danke,

hört sich gut an. Das ganze scheint mir auch noch stark verbesserungswürdig zu sein.
ich habe Deinen Vorschalg gerade mal ausprobiert und leider feststellen müssen, dass das so nicht funktioniert. ich weiß auch nicht woran das liegt.

mein Programm soll eigentlich mehrere Bilder einlesen und dann das bearbeitete anzeigen.
das Einlesen erfolgt in einem Thread. Ich wollte dann mit validaterect auslösen, dass der Bereich neu gezeichnet wird. hättest Du dafür einen besseren Ansatz, damit ich gleich in die richtige Richtung starte.
 
ich habe es doch hingekriegt. weiß nicht genau, was falsch war.

Gruß Jower

Code:
void CMyView::OnDraw(CDC* pDC)
{
	CVisualServoDoc* pDoc = GetDocument();

	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	CvvImage m_CvvImage;
	RECT rect;
	GetDlgItem(IDC_IMAGE)->GetWindowRect(&rect);
	ScreenToClient(&rect);
	m_image = cvLoadImage( "./test.png", 0);
	m_CvvImage.CopyOf( m_image, 1);
	m_CvvImage.DrawToHDC( pDC->m_hDC, &rect);

	ReleaseDC(pDC);

	UpdateData();
}
 
Hallo Jower,

deinen Ansatz finde ich ok und wenn man lange genug mit der Antwort wartet, erledigen sich auch die Implementierungsprobleme :)

ReleaseDC() solltest du jetzt nicht mehr aufrufen, da du den von OnDraw() gelieferten Device Context (pDC) verwendet. Das ist nur notwendig, wenn du GetDC() benutzt.
Das UpdateData() ist auch überflüssig.

Grüße
MCoder
 
danke für die Hilfe.

eine kleine Frage hätte ich aber noch.

Ich habe ja gesagt, dass das Programm immer, wenn es ein Bild bearbeitet hat, das Bild darstellen soll. Ist es eigentlich geschickt, das über OnDraw zu machen, bzw. wie müßte ich denn OnDraw auslösen. Ich hatte das erstmal in Ondraw gemacht, um ein wenig firm mit den DC´s zu werden. Validate war mein Plan funktioniert aber nicht so wie erhofft.
Hast Du da ein Idee?

Gruß Jower
 
Hallo,

du musst Invalidate() bzw. InvalidateRect() aufrufen. Damit wird eine WM_PAINT Message ausgelöst, die dann zu führt, dass OnDraw() aufgerufen wird.
Mit ValidateRect() erreichst du das genaue Gegenteil: Der angegebene Bereich wird vom Neuzeichnen ausgenommen.

Gruß
MCoder
 
genau, das meinte ich auch.

das geht aber anscheinend nicht von meinem Verarbeitungsthread (Abgeleitet von WinThread) aus, dabei dachte ich, dass man Messages von überall schicken kann.
(noch besser wäre, wenn man sie auch überall verarbeiten könnte ;) )
Scheint aber nicht anzukommen.

Weißt Du was ich falsch mache?

Gruß Jower
 

Neue Beiträge

Zurück