Vykreslenie Bitmapy v PictureBoxe – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Vykreslenie Bitmapy v PictureBoxe – C / C++ – Fórum – Programujte.comVykreslenie Bitmapy v PictureBoxe – C / C++ – Fórum – Programujte.com

 

maniks0
Newbie
13. 10. 2010   #1
-
0
-

Zdravim,

zasekol som sa na jednom probleme, s ktorym si neviem dat rady a chcel by som Vas poprosim o rady. Moja aplikacia v podstate zachytava obraz z kamery a rendruje ho na obrazovku do PictureBox-u (o to sa stara API vyrobcu kamery, neviem ako tie metody vo vnutri funguju). Ja potrebujem zachyteni obraz zanalyzovat a po analyze ho vykreslit do dalsieho PictureBox-u. GUI mam pisane v C#, ale vsetko ostatne riesim v C++ pokial mozno s pouzitim WIN32 API. Skusim Vam podrobne popisat dany problem ktory mam.

HANDLE PictureBoxu predam z C# do C++



adapter.Init(0, analyzeBox.Handle.ToInt32());



int Device::Init(int phf, int handleWindow)
{
HWND analyzeWindowHandle = (HWND) handleWindow;
...
}


Analyzu volam hned po vyrendrovani zachyteneho obrazu z kamery do prveho PixtureBoxu, takze tie obrazove data sa stale nachadzaju v pamati. Na vyber dat z pamate pouzivam zase API funkciu kamery. Pre lepsie pochopenie prilozim popis tejto funkcie.


Syntax

INT is_InquireImageMem (HIDS hCam,
char* pcMem, int nID,
int* pnX, int* pnY,
int* pnBits, int* pnPitch);

Description

is_InquireImageMem() reads out the properties of an allocated image memory.

Input Parameters

hCam - Camera handle

pMem - Pointer to the starting address of the image memory as allocated by is_AllocImageMem()

NID - ID of the image memory as allocated by is_AllocImageMem()

pnX - Returns the width used to define the image memory (can be 0).

pnY - Returns the height used to define the image memory (can be 0).

pnBits - Returns the bit width used to define the image memory (can be 0).

pnPitch - Returns the line increment of the image memory (can be 0).


Takze v metode Analyze nacitam data z pamate, prebehnem to dakym tym algoritmom a chcem ich vykrelist do pripraveneho PictureBoxu. A to je ten problem. Neviem ako na to. Z debugu sa zda ze cez CreateBitmap sa Bitmapa v pohode vytvori, problem je, ze neviem ako ju zobrazit do PictureBox-u s vyuzitim HWND. Momentalne to skusam pomocou SendMessage, ale to mi tiez nefunguje.


int Device::Analyze()
{
int width, height, bits, pitch;
char* tempBitmap;

int rValue;
if(is_InquireImageMem (*this->cameraHandlePointer, this->imgMemory, this->imgMemoryID, &width ,&height, &bits, &pitch) != IS_SUCCESS)
return rValue;
else
{
tempBitmap = imgMemory;

HBITMAP hBmp = CreateBitmap(width,height,1,bits,tempBitmap);

LRESULT lr = SendMessage( this->analyzeWindowHandle, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBmp);

}
return 0;
}


Vopred dakujem za napady, rady, tipy, triky, alebo myslienky

Nahlásit jako SPAM
IP: 178.40.142.–
liborb
~ Redaktor
+18
Guru
14. 10. 2010   #2
-
0
-

Začnu trochu od lesa. Z kamery dostaneš data, která chceš vykreslit do PictureBoxu nebo jinam (není důvod, aby to byl přímo PB :)). První problém, který vidím, je ten, že bitmapu tvoříš pro každý snímek, což by bylo značně neefektivní a pomalé. Z kamery budeš asi dostávat obrázek stále stejné velikosti, takže si vytvoříš jednu bitmapu, kterou budeš pořád používat (v podstatě je to možné brát jako alokovanou paměť). Data do bitmapy budeš dostávat funkcí SetDIBits. A následně budeš bitmapu vykreslovat do DC formuláře nebo ovládacího prvku, který si vybereš.

Získej HWND toho ovládacího prvku, přes GetDC získej jeho HDC, vytvoř si kompatibilní HDC, vytvoř si kompatibilní bitmapu (to je ta bitmapa, do které budeš cpát data z kamery) a pak přes BitBlt to nacpeš z paměťové bitmapy do oblasti formuláře/ovládacího prvku. Můžeš se částečně inspirovat zde http://programujte.com/?akce=diskuze&kam=vlakno&tema=14929-bitmapa. Když tak se ptej :)

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
14. 10. 2010   #3
-
0
-

Tak skusil som co si mi poradil



int Device::Analyze()
{
int width, height, bits, pitch, tempBitmapID;
int rValue;
char* tempBitmap = (char*) malloc((this->width * ((this->bits + 1) / 8) + 0) * this->height);

if(rValue = is_CopyImageMem(*this->cameraHandlePointer, imgMemory, imgMemoryID, tempBitmap) != IS_SUCCESS)
return rValue;

if(is_InquireImageMem (*this->cameraHandlePointer, imgMemory, imgMemoryID, &width ,&height, &bits, &pitch) != IS_SUCCESS)
return rValue;
else
{
...

BITMAPINFO Bmi={0};
Bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
Bmi.bmiHeader.biWidth = width;
Bmi.bmiHeader.biHeight = height;
Bmi.bmiHeader.biPlanes = 1;
Bmi.bmiHeader.biBitCount = bits;
Bmi.bmiHeader.biCompression = BI_RGB;
Bmi.bmiHeader.biSizeImage = width*height*bits/8;

HDC hDc = GetDC(this->analyzeWindowHandle);
HDC chDc = CreateCompatibleDC(hDc);
HBITMAP hBmp = CreateCompatibleBitmap(hDc, width, height);
if(SetDIBits(chDc, hBmp, 0, height, tempBitmap, &Bmi, DIB_RGB_COLORS) == ERROR_INVALID_PARAMETER)
return 0;
BOOL ok = BitBlt(hDc,0,0,width,height,chDc,0,0,SRCCOPY);

DWORD d = GetLastError();
}
return 0;
}


V PictureBox-e sa mi nezobrazi nic. Pritom GetDC, CreateCompatibleDC aj HBITMAP mi vrati normalne handle. SetDIBits mi vrati 576 co je vlastne height a BitBlt mi vrati true... Tak troska nerozumiem, kde je problem?

Nahlásit jako SPAM
IP: 178.40.142.–
maniks0
Newbie
14. 10. 2010   #4
-
0
-

Neviem na kolko je to uzitocna informacia, ale ked tam hodim

BitBlt(hDc,0,0,width,height,chDc,0,0,WHITENESS);

tak sa mi PictureBox zfarbi na bielo

Nahlásit jako SPAM
IP: 178.40.142.–
liborb
~ Redaktor
+18
Guru
15. 10. 2010   #5
-
0
-

Je to užitečná informace, protože alespoň vidíš, že to něco dělá :)
V kódu ti chybí "spárování" kompatibilních HDC a HBITMAP přes SelectObject:

/*hOldBmp = */SelectObject(chDc, hBmp);

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
15. 10. 2010   #6
-
0
-

Vdaka Ti, funguje to :)

Este sa chcem opytat jednu vec. Namiesto BitBlt som pouzil StretchBlt, ktora mi bitmapu prisposobi na vystupny prvok, kedze moj PictureBox ma mensie rozmery ako bitmapa. Chcel by som dynamicky zistit rozmery toho prvku a zase jedine co poznam je jeho HWND. Da sa to? Alebo si ich musim predat ako parametre?

StretchBlt(hDc,0,0,438,329,chDc,0,0,width,height,SRCCOPY);

Nahlásit jako SPAM
IP: 178.40.142.–
liborb
~ Redaktor
+18
Guru
15. 10. 2010   #7
-
0
-

Pokud chceš používat StretchBlt, tak nezapomeň nastavit mód přes SetStretchBltMode, aby to bylo "hezoučké" :), ale zase počítej, že to bude znatelně pomalejší.

A dále ... získat rozměry samozřejmě lze. Když máš HWND, tak máš všechno :). GetClientRect je ta správná funkce na získání velikosti obdélníka (vnitřní klientská oblast).

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
15. 10. 2010   #8
-
0
-

Nepotrebujem to mat hezoucke :) kedze detekujem farby, vykreslim len najdene farbi a zvysok obrazka je cierny. Co sa tyka tej rychlosti, to by aj mohol byt problem. Nejaka rychla alternativa k StretchBlt? Zmensenie obrazku v pamati neprichadza do uvahy, potrebujem s nim pracovat s takym aky je, len vykreslit ho mensi.

To co si hovoril na zaciatku o pouziti jednej bitmapy este samozrejme vykonam a budem tam len sypat tie bity cez SetDIBits ;)

Nahlásit jako SPAM
IP: 178.40.142.–
liborb
~ Redaktor
+18
Guru
15. 10. 2010   #9
-
0
-

Rychlá alternativa k StretchBlt? Na úrovni GDI není .. buď použít BitBlt (v podstatě prosté kopírování paměti) nebo použít pro StretchBlt mód COLORONCOLOR (vynechávání pixelů). O jiné možnosti s GDI nevím. Pokud vím, tak GDI+ je ještě o něco pomalejší :), takže pak jedině jestli existuje něco (OpenGL, D3D, D2D apod.) s HW akcelerací pro tyhle operace.

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
21. 10. 2010   #10
-
0
-

Prosim Ta narazil som na dasli problem...

zase cez nejaku api funkciu kamery som si vybral AOI (Area of interest - nejaka oblast obrazka) z obrazku. Pri tomto proceses sa prehravanie stopne, nastavi sa AOI, ulozim novu sirku a vysku do instancnych premmenych, uvolnim pamat a znova spustim video. Pri spusteni znova nastavujem vsetky DC, no proste cely proces co sme tu riesili. Ked prejdem na analyzu, skopirujem pamat, zanalyzjem, nahram tie bity cez setDIBits a cez BitBlt to chcem zobrazit.

Problem je ze to nezobrazi =-O Pritom je to uplne ten isty proces ako pri prehravani obrazkou s defaultnou velkostou. Spravil som si taky test, najprv mi to bezi na default velkost, tu sa vysledok analyzy zobrazi, potom si vyberiem tu AOI a v prvku kde sa zobrazuje analyza zostane posledny frame z tej predchadzajucej. Ked pri defaultnej velkosti analyzu vypnem a spustim ju az po vybere AOI (takze picturebox je stale "cisty"), nezobrazi sa nic. BitBlt mi vracia 0, co je nejaka chyba, ale aka ked vsetko ostatne prebehne ok?

Nahlásit jako SPAM
IP: 78.108.145.–
liborb
~ Redaktor
+18
Guru
21. 10. 2010   #11
-
0
-

Jednak ... pokud ti BitBlt vrací 0, tak se dá přes GetLastError zjistit o jakou chybu se jedná. Někdy to i pomůže :)

A druhá věc ... ty máš data z kamery ... řekněme 800x600 a pak chceš jenom výřez, který je bude buď menší (třeba 400x300) nebo je to ten případ, kdy kamera udělá preciznější snímek s větším rozlišením (1600x1200). Tak či tak je potřeba jít touto cestou - když vytváříš bitmapu v paměti, tak ji vytvoř na maximální rozměr, který můžeš dosáhnout (v mé ukázce je to 1600x1200) a pak už to s tou bitmapu vydrž :) až do konce, tj. žádné uvolnění paměti a vytvoření nové s jinými rozměry. Prostě jenom využiješ tu menší tu větší část. V BltBit stejně uvádíš jak velký rozměr chceš kopírovat a to je to místo, kde se ti to bude měnit podle aktuálních potřeb.

Problém je totiž v tom, že sice všechno krásně roste ... máš stovky GB RAM a možná už TB disk, ale počet GDI objektů je stále omezen, takže je potřeba s vytvářením GDI objektů šetřit, jak se jen dá :)

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
21. 10. 2010   #12
-
0
-

GetLastError mi vrati "6", netusim co to znemena...

Mne ide prave o to. Zhruba 20% obrazka absolutne nevyuzijem - znizit naroky na pamat, tym ze zmensim spracovavany obrazok a tym padom aj celu analyzu urychlim.

Funguje mi to jedine ked video stopnem, nastavim AOI a znova spustim. Bez realokacie pamate. Tam je vsak tiez problem ze bitmapa ma stale povodne rozlisenie a nevyuzite pixeli zostanu tak ako boli pred nastavenim AOI.

Vid ukazka: http://img257.imageshack.us/img257/8571/ukazkal.jpg

Tymto to cele v podstate straca zmysel, sice by som mohol prechadzat bitmapu len v rozliseni AOI a na ostatne kaslat, ale pamat by to zralo stale tu istu.

Ja tomu proste netozumiem preco to nezobrazi. Ved na zaciatku si takym istym sposobom naalokujem pamat 768x576 a tam to ide. Ked vsak pamat uvolnim a alokujem novu, mensiu, uz to nejde...

PS: skusil som si po analyze, pred BitBlt ulozit bitmapu na disk. Vyzera presne tak ako ma, ma rozmeri ake som si vybral, takze problem moze byt uz jedine len v SetDIBits (nepredopokladam, vrati mi pocet riadkov) alebo BitBlt...



SetDIBits(this->chDc, this->hBmp, 0, this->height, tempBitmap, &this->bmi, DIB_RGB_COLORS);
//StretchBlt(hDc,0,0,this->rect.right,this->rect.bottom,this->chDc,0,0,this->width,this->height,SRCCOPY);
BitBlt(hDc,0,0,this->width, this->height, chDc, 0,0,SRCCOPY);

Nahlásit jako SPAM
IP: 78.108.145.–
liborb
~ Redaktor
+18
Guru
21. 10. 2010   #13
-
0
-

Chyba 6 je ERROR_INVALID_HANDLE (http://msdn.microsoft.com/en-us/library/ms681382(v=VS.85).aspx), takže to HDC není asi platné nebo tak něco. Máš tu novou bitmapu a paměťové DC spárované? Je tam dost možností, kde můžeš mít chybu :).

A druhá věc ... tu paměť si alokoval, takže tím, že ji využíváš, už nezvyšuješ paměťové nároky. No a pokud chceš urychlit zpracování obrázku, tak to přece uděláš tak, že té funkci, která to zpracovává předhodíš ty menší rozměry, ale paměť můžeš být "ta velká".

Jinak si to samozřejmě dělej dle svého :) ... další možnost je mít ty paměťové bitmapy (a DC) 2, aby si je nemusel pořád vytvářet znovu a znovu.

Nahlásit jako SPAM
IP: 78.80.52.–
maniks0
Newbie
22. 10. 2010   #14
-
0
-



if(this->hDc == (HDC)0xCDCDCDCD && this->chDc == (HDC)0xCDCDCDCD)
{
this->hDc = GetDC(this->analyzeWindowHandle);
this->chDc = CreateCompatibleDC(this->hDc);
}


Tymto je to vyriesene. Z nejakych mne neznamych dovodov bol problem pri pridavani novych hodnot. Takto sa tie DC naplnia iba raz.

Ten odkaz je uz zabookovani ;)

Inak ja vzdy vytvaram kopiu celej pamate, preto by mi moc nepomohlo keby som mal alokovanu velku pamat a nevyuzitu naplno, skopirovat by som ju musel aj tak celu, hoci potom by som mohol prechadzat len vybrannu tu cast.
A mozem povedat ze sa to vyditelne zrychlilo :)

Vdaka ti dobra dusa, na dnes to je asi vsetko :)

Nahlásit jako SPAM
IP: 95.102.187.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 25 hostů

Podobná vlákna

Okruhly obrazok v pictureBoxe? — založil Eversmann

Vykreslenie obrázku — založil Majo

Vykreslenie grafov — založil Anonymní uživatel

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý