1Danke
ERLEDIGT
JA
JA
ANTWORTEN
5
5
ZUGRIFFE
886
886
EMPFEHLEN
-
Einen schönen Abend!
Ich habe ein kleines Programmchen in MFC gebastelt, welches ein bestimmtes Bild in verschiedenen Kanäle splittert.
hier die Funktion:
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
CBitmap tempbmp; CString fileName; CFileDialog dlg(TRUE,NULL,NULL,OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST, L"Bitmap(*.bmp)|*bmp||",this,0,TRUE); if (dlg.DoModal() == IDOK) { fileName = dlg.GetPathName(); HBITMAP hBmp = (HBITMAP)::LoadImage( NULL, fileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION ); tempbmp.Attach(hBmp); CClientDC dc(this); CDC cDC; cDC.CreateCompatibleDC(&dc); CBitmap *pOldbmp = cDC.SelectObject(&tempbmp); BITMAP bi; tempbmp.GetBitmap(&bi); dc.BitBlt(0,0,bi.bmWidth,bi.bmHeight,&cDC,0,0,SRCCOPY); cDC.SelectObject(pOldbmp); for (int i=0; i<bi.bmWidth; i++) { for (int j=0; j<bi.bmHeight; j++) { BYTE r,g,b,y,u,v; COLORREF rgb= RGB(0,0,0); rgb = dc.GetPixel(i,j); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); //y = 0,299*r +0,587*g +0,114*b; //alt y = ( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16; u = ( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128; v = ( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128; /* Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16 U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128 V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128 C = Y - 16 D = U - 128 E = V - 128 R = clip(( 298 * C + 409 * E + 128) >> 8) G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) B = clip(( 298 * C + 516 * D + 128) >> 8) */ dc.SetPixel(i+bi.bmWidth,j,RGB(y,y,y)); dc.SetPixel(i,j+bi.bmHeight,RGB(u,u,u)); dc.SetPixel(i+bi.bmWidth,j+bi.bmHeight,RGB(v,v,v)); } } } else { }
Das Problem ist nur, dass man sieht, wie die die 3 Kanäle (bilder) gezeichnet werden :
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
for (int i=0; i<bi.bmWidth; i++) { for (int j=0; j<bi.bmHeight; j++) { BYTE r,g,b,y,u,v; COLORREF rgb= RGB(0,0,0); rgb = dc.GetPixel(i,j); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); //y = 0,299*r +0,587*g +0,114*b; //alt y = ( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16; u = ( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128; v = ( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128; /* Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16 U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128 V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128 C = Y - 16 D = U - 128 E = V - 128 R = clip(( 298 * C + 409 * E + 128) >> 8) G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) B = clip(( 298 * C + 516 * D + 128) >> 8) */ dc.SetPixel(i+bi.bmWidth,j,RGB(y,y,y)); // Hier wird es mit jedem Durchlauf gezeichnet :-( dc.SetPixel(i,j+bi.bmHeight,RGB(u,u,u)); dc.SetPixel(i+bi.bmWidth,j+bi.bmHeight,RGB(v,v,v)); } }
Wie kann man erst zeichnen, wenn die Schleife komplett durchlaufen ist? (so dass, das BIld gleich "komplett" angezeigt wird )
Noch eine Frage: Wenn ich das Fenster minimiere oder schiebe, verschwindet die Zeichnung. Was kann man dagegen tun?
-
1)
Erstelle dir eine neue Bitmap mit dem richtigen Dimensionen und male die Kanäle da hinein. Nicht direkt auf den ClientDC zeichnen. Daran hängt dann auch das zweite Problem:
2)
In OnPaint (WM_PAINT) wird dann natürlich dein Bild wieder übermalt. In OnPaint machst du dann einfach ein simples BitBlt von deiner Puffer-Bitmap auf den PaintDC. Geht dann auch schneller.
Merke: Man sollte nie ausserhalb von WM_PAINT schreibend auf den DC des Fensters zugreifen.
-
Ich habe mein Code bisschen geändert, nun wird es neu gezeichnet, wenn ich das Fenster minimiere oder seine Größe ändere.
Problem ist nur, dass ich immernoch sehe, wie das BIld aufgebaut wird.
Meine Situation:
Ich taste das Bild aus ClientDC (bei mir dc-Variable), dann schreibe ich die Werte für Y,U,V in Memory Device Context (cDC bei mir)
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
CBitmap tempbmp; HBITMAP hBmp = (HBITMAP)::LoadImage( NULL, myDatei, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION ); tempbmp.Attach(hBmp); CClientDC dc(this); CDC cDC; cDC.CreateCompatibleDC(&dc); CBitmap *pOldbmp = cDC.SelectObject(&tempbmp); BITMAP bi; tempbmp.GetBitmap(&bi); dc.BitBlt(0,0,bi.bmWidth,bi.bmHeight,&cDC,0,0,SRCCOPY); // Hier wird das erste (original) Bild sofort gezeigt cDC.SelectObject(pOldbmp); for (int i=0; i<bi.bmWidth; i++) //Hier laufe ich durch das Bild (das was auf ClientDC gezeichnet wurde) { for (int j=0; j<bi.bmHeight; j++) { BYTE r,g,b,y,u,v; COLORREF rgb= RGB(0,0,0); rgb = dc.GetPixel(i,j); //Hier lese ich jeden Pixel aus! r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); //y = 0,299*r +0,587*g +0,114*b; //alt y = ( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16; u = ( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128; v = ( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128; /* Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16 U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128 V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128 C = Y - 16 D = U - 128 E = V - 128 R = clip(( 298 * C + 409 * E + 128) >> 8) G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) B = clip(( 298 * C + 516 * D + 128) >> 8) */ cDC.SetPixel(i+bi.bmWidth,j,RGB(y,y,y)); //Hier schreibe ich alle Werte in Memory Device Context (glaube ich zumindest :-) ) cDC.SetPixel(i,j+bi.bmHeight,RGB(u,u,u)); cDC.SetPixel(i+bi.bmWidth,j+bi.bmHeight,RGB(v,v,v)); } }
Im Post oben stand, dass ich neues BITMAP erstellen soll und da rein malen
. Wie kann ich das erreichen? Gibt es eine Funktion, mit der ich aus CDC in BITMAP schreiben kann und dann alles zeigen (sofort, ohne dem lahmen Aufbau) ?
Ach ja, wenn ich z.B. das Fenster so schiebe, dass es nur teilweise gezeigt wird und ein Teil davon nicht zu sehen ist--->und dann wieder so auf dem Desktop platziere, dass es komplett zu sehen ist, hängt die Anwendung bisschen, weil die 3 neue Bilder gezeichnet werden. (hier im Code schreibe ich in cDC, so dass man nichts sieht, aber die Belastung durch das Zeichnen spürbar ist.
-
Jedes CDC kann an eine Bitmap gehängt werden (SelectObject, hast du ja oben auch schon mal gemacht). Du kannst mit CreateCompatibleBitmap eine erstellen.
Evtl. anderer Vorschlag: Arbeite mit DIBSections. Die kannst du ähnlich wie Bitmaps benutzen, aber du bekommst auch einen Pointer auf die Daten. SetPixel/GetPixel schlagen nämlich nicht wirklich Geschwindigkeitsrekorde.
-
Ich habe mein Programm bisschen geändert, so dass es nun sofort und deutlich schneller angezeigt wird und alle möglichen "Verformungen" des Fensters sind jetzt möglich ohne, dass das Bild verloren geht oder langsam aufgebaut wird.
Problem ist nur, wenn ich mein Menüpunkt wieder aufrufe, kommt es zu einem Fehler.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
void Ccolor2bwView::OnDraw(CDC* /*pDC*/) { Ccolor2bwDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: Code zum Zeichnen der systemeigenen Daten hinzufügen CClientDC mainDC(this); switch (WasMaleIch) { case 1: { //cDC.RestoreDC(savedDcInt); mainDC.BitBlt(0,0,2*bi.bmWidth,2*bi.bmHeight,&cDC,0,0,SRCCOPY); } break; } }Code :1 2 3 4
void Ccolor2bwView::OnToolsB() //Menüaufruf { Dialog1(); }Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
void Ccolor2bwView::FarbeZuGrau() { CBitmap tempbmp; HBITMAP hBmp = (HBITMAP)::LoadImage( NULL, myDatei, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION ); tempbmp.Attach(hBmp); CClientDC dc(this); cDC.CreateCompatibleDC(&dc); // Ich glaube der Fehler passiert hier beim zweiten Aufruf (wenn ich den Menüpunkt auswähle) CBitmap *pOldbmp = cDC.SelectObject(&tempbmp); tempbmp.GetBitmap(&bi); dc.BitBlt(0,0,bi.bmWidth,bi.bmHeight,&cDC,0,0,SRCCOPY); CBitmap pufferBmp; pufferBmp.CreateCompatibleBitmap(&dc,2*bi.bmWidth,2*bi.bmHeight); cDC.SelectObject(&pufferBmp); for (int i=0; i<bi.bmWidth; i++) { for (int j=0; j<bi.bmHeight; j++) { BYTE r,g,b,y,u,v; COLORREF rgb= RGB(0,0,0); rgb = dc.GetPixel(i,j); r = GetRValue(rgb); g = GetGValue(rgb); b = GetBValue(rgb); //y = 0,299*r +0,587*g +0,114*b; //alt y = ( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16; u = ( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128; v = ( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128; /* Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16 U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128 V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128 C = Y - 16 D = U - 128 E = V - 128 R = clip(( 298 * C + 409 * E + 128) >> 8) G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) B = clip(( 298 * C + 516 * D + 128) >> 8) */ cDC.SetPixel(i,j,RGB(r,g,b)); cDC.SetPixel(i+bi.bmWidth,j,RGB(y,y,y)); cDC.SetPixel(i,j+bi.bmHeight,RGB(u,u,u)); cDC.SetPixel(i+bi.bmWidth,j+bi.bmHeight,RGB(v,v,v)); } } //savedDcInt = cDC.SaveDC(); dc.BitBlt(0,0,2*bi.bmWidth,2*bi.bmHeight,&cDC,0,0,SRCCOPY); }irgendwie scheint das Programm nicht klar kommen, wenn ich mein cDC beim zweiten Menüaufruf neu kreiereCode :1 2 3 4 5 6 7 8 9 10 11 12 13 14
void Ccolor2bwView::Dialog1(void) { CFileDialog dlg(TRUE,NULL,NULL,OFN_ENABLESIZING|OFN_EXPLORER|OFN_FILEMUSTEXIST, L"Bitmap(*.bmp)|*bmp||",this,0,TRUE); if (dlg.DoModal() == IDOK) { myDatei = dlg.GetPathName(); FarbeZuGrau(); WasMaleIch = 1; } else { } }
mit cDC.CreateCompatibleDC(&dc);
Wie kann ich es umgehen? Soll ich cDC.CreateCompatibleDC(&dc); irgendwo beim Start des Programms machen oder liegt es an was anderes?
P.S. Diese Variablen sind in *.h Datei deklariert.
Code :1 2 3 4
CString myDatei; BITMAP bi; int savedDcInt; CDC cDC;
Geändert von Albus (30.03.10 um 15:34 Uhr)
-
13.04.10 11:58 #6CTecS Tutorials.de Gastzugang
In OnDraw der Aufruf von CClientDC mainDC(this);ist totaler mist den dc auf dein Window bekommst du doch übergeben, du mußt nur den Kommentar weg nehmen dann hast du in pDC den Zeiger auf den WindowsDC den du zum Zeichnen benötigst.
Die Aussage das du DIBSections benutzen sollst damit du an die Daten des Bitmaps kommst ist ja nun auch nur eine Halbwahrheit, denn bei CBitmap kommt man genau so an die Daten.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
void CPicture::MakeGrayPicture() { if(!this->m_hObject) { TRACE( _T("CPicture::MakeGrayPicture Class not Initialised or not Picture Loaded\n")); return; } CPalette pal; UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256); LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; pLP->palVersion = 0x300; pLP->palNumEntries = 256; for( int i=0; i < 256; i++) { pLP->palPalEntry[i].peRed = i; pLP->palPalEntry[i].peGreen = i; pLP->palPalEntry[i].peBlue = i; pLP->palPalEntry[i].peFlags = 0; } pal.CreatePalette( pLP ); BITMAP bm; CBitmap::GetObject(sizeof(BITMAP), (LPSTR)&bm); BYTE *bmpBuffer = new BYTE[ bm.bmWidthBytes*bm.bmHeight ];//allocate memory for image //byte buffer ULONG dwValue=CBitmap::GetBitmapBits(bm.bmWidthBytes*bm.bmHeight, bmpBuffer);//Get the bitmap bits //into a structure*/ DWORD* buffer = (DWORD*)bmpBuffer; for(ULONG Count = 0;Count < dwValue/4;Count++) { UINT Index = pal.GetNearestPaletteIndex(buffer[Count]); buffer[Count] = RGB(pLP->palPalEntry[Index].peRed, pLP->palPalEntry[Index].peGreen, pLP->palPalEntry[Index].peBlue); } delete[] pLP; dwValue = CBitmap::SetBitmapBits(bm.bmWidthBytes*bm.bmHeight,bmpBuffer); delete[] bmpBuffer; }
das ist mal eine Funktion aus einer Klasse die von CBitmap abgeleitet ist. Wenn du die CBitmap-aufrufe etwas veränderst hast du schon deine fertige Funktion. Das alles noch in ein Bitmap geschrieben was du dann in OnDraw nur noch Blittest und fertig.
Das Zielbitmap kannst du gleich in der Headerdatei erstellen und beim Initialisieren mit erstellen, fertig ist deine Anwendung.
Noch Fragen?
Ähnliche Themen
-
Link erst anklickbar wenn Seite komplett fertig geladen ist
Von rollerueckwaerts im Forum Javascript & AjaxAntworten: 3Letzter Beitrag: 30.12.09, 00:46 -
Div erst anzeigen wenn geladen
Von xThorx im Forum Javascript & AjaxAntworten: 4Letzter Beitrag: 17.03.05, 13:35 -
Seite erst anzeigen wenn ganz geladen
Von AnTiUsEr im Forum Javascript & AjaxAntworten: 1Letzter Beitrag: 29.06.04, 20:08 -
Bild erst anzeigen wenn ganz geladen ?
Von toboli im Forum Javascript & AjaxAntworten: 1Letzter Beitrag: 25.03.04, 17:59 -
Seite erst anzeigen wenn fertig geladen?
Von maho15 im Forum Javascript & AjaxAntworten: 5Letzter Beitrag: 16.08.02, 19:49





Zitieren
Login






