webcam取像後無法二值化問題 |
答題得分者是:istillloving
|
eulor2000
一般會員 發表:51 回覆:34 積分:17 註冊:2008-11-18 發送簡訊給我 |
我第一次用webcam取像確無法將圖片二值化,請資深板友指導....^^ 程式如下: //--------------------------------------------------------------------------- void __fastcall TForm1::N6Click(TObject *Sender) { Byte *ptr,*ptr1;//用來指像素行的指標 int r,g,b;//rgb三原色 int grey=0; Graphics::TBitmap *Bmp=new Graphics::TBitmap(); Graphics::TBitmap *TemBmp=new Graphics::TBitmap(); Bmp->PixelFormat=pf24bit; Image1->Picture->Assign(Bmp); capEditCopy(cap1); if(Clipboard()->HasFormat(CF_DIB)) { Bmp->Assign(Clipboard()); } for(int d = 0; d { ptr =(Byte *)Bmp->ScanLine[d]; //該行像素位址給ptr for(int c = 0; c { b=ptr[c*3]; //該點第一個位子是藍色 g=ptr[c*3 1]; //該點第二個位子是綠色 r=ptr[c*3 2]; //該點第三個位子是紅色 if((b==255&&g==255&&r==255)) //如果是白色維持原來若不是變成黑色 grey=255; //0:代表black 255:代表白 else grey=0; ptr[c*3]=(Byte)grey; //存回bgr值 ptr[c*3 1]=(Byte)grey; ptr[c*3 2]=(Byte)grey; } } Image1->Picture->Bitmap=Bmp; delete Bmp; |
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
您好:
可不可PO完整的 我剛剛試了單張影像的沒有問題呢 你的Image1是右邊還左邊阿 右邊好像是Panel呢 而且 Byte *ptr,*ptr1;//用來指像素行的指標 int r,g,b;//rgb三原色 int grey=0; Graphics::TBitmap *Bmp=new Graphics::TBitmap(); Graphics::TBitmap *TemBmp=new Graphics::TBitmap(); Bmp->PixelFormat=pf24bit; Image1->Picture->Assign(Bmp); //// 這一行應該Bmp沒有值吧.........
------
恩...
編輯記錄
istillloving 重新編輯於 2009-11-17 12:48:40, 註解 無‧
istillloving 重新編輯於 2009-11-17 13:02:59, 註解 無‧ istillloving 重新編輯於 2009-11-17 16:13:35, 註解 無‧ |
eulor2000
一般會員 發表:51 回覆:34 積分:17 註冊:2008-11-18 發送簡訊給我 |
|
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
|
阿信
版主 發表:111 回覆:983 積分:813 註冊:2005-03-10 發送簡訊給我 |
|
eulor2000
一般會員 發表:51 回覆:34 積分:17 註冊:2008-11-18 發送簡訊給我 |
-我按你方式改過還是不行.....請問你有執行我範例程式?.....那會這樣...救救我
===================引 用 阿信 文 章=================== > if((b==255&&g==255&&r==255)) //如果是白色維持原來若不是變成黑色 > grey=255; //0:代表black 255:代表白 > else > grey=0; 上面這段錯了! 這樣寫會整個輸出黑色! 應該改寫成如下: grey=(b g r)/3; //不使用標準亮度公式,可避開浮點運算 if (grey>128) grey=255; //128是閥值,也就是黑跟白的分界點 else grey=0; 阿信~
編輯記錄
eulor2000 重新編輯於 2009-11-19 00:23:01, 註解 無‧
|
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
他說的那個只是你邏輯錯誤
可是沒道理Image的影像會和WEBCAM一樣 程式碼你又不捨得PO怎麼搞 ===================引 用 eulor2000 文 章=================== -我按你方式改過還是不行.....請問你有執行我範例程式?.....那會這樣...救救我 ===================引 用 阿信 文 章=================== > if((b==255&&g==255&&r==255)) //如果是白色維持原來若不是變成黑色 > grey=255; //0:代表black 255:代表白 > else > grey=0; 上面這段錯了! 這樣寫會整個輸出黑色! 應該改寫成如下: grey=(b g r)/3; //不使用標準亮度公式,可避開浮點運算 if (grey>128) grey=255; //128是閥值,也就是黑跟白的分界點 else grey=0; 阿信~
------
恩... |
eulor2000
一般會員 發表:51 回覆:34 積分:17 註冊:2008-11-18 發送簡訊給我 |
[code cpp] /--------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; HWND cap1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::N2Click(TObject *Sender) { cap1=capCreateCaptureWindow( "My cap", WS_CHILD | WS_VISIBLE, 0,0,Panel1->Width, Panel1->Height, Panel1->Handle, 0); bool a = false; for( int i = 0; i < 10; i ) { a = capDriverConnect( cap1, i ); if( a ) break; } if( !a ) { ShowMessage("攝影機連接失敗-.-"); } capOverlay(cap1,true); capPreview(cap1,true); capPreviewRate(cap1, 33); } //--------------------------------------------------------------------------- void __fastcall TForm1::N6Click(TObject *Sender) { Byte *ptr,*ptr1;//用來指像素行的指標 int r,g,b;//rgb三原色 int grey=0; Graphics::TBitmap *Bmp=new Graphics::TBitmap(); Graphics::TBitmap *TemBmp=new Graphics::TBitmap(); Bmp->PixelFormat=pf24bit; Image1->Picture->Assign(Bmp); capEditCopy(cap1); if(Clipboard()->HasFormat(CF_DIB)) { Bmp->Assign(Clipboard()); Image1->Picture->Assign(Bmp); } for(int d = 0; d { ptr =(Byte *)Bmp->ScanLine[d]; //該行像素位址給ptr for(int c = 0; c { b=ptr[c*3]; //該點第一個位子是藍色 g=ptr[c*3 1]; //該點第二個位子是綠色 r=ptr[c*3 2]; //該點第三個位子是紅色 if((b==255&&g==255&&r==255)) //如果是白色維持原來若不是變成黑色 grey=255; //0:代表black 255:代表白 else grey=0; ptr[c*3]=(Byte)grey; //存回bgr值 ptr[c*3 1]=(Byte)grey; ptr[c*3 2]=(Byte)grey; } } Image1->Picture->Bitmap=Bmp; delete Bmp; } //--------------------------------------------------------------------------- void __fastcall TForm1::N4Click(TObject *Sender) { Close(); } //--------------------------------------------------------------------------- [/code] 我有附上整個程式原始檔在樓上第三篇超連結處delphi.ktop.com.tw/board.php
編輯記錄
eulor2000 重新編輯於 2009-11-19 12:48:13, 註解 無‧
|
阿信
版主 發表:111 回覆:983 積分:813 註冊:2005-03-10 發送簡訊給我 |
程式應修改如下:
[code cpp] void __fastcall TForm1::N6Click(TObject *Sender) { Byte *ptr,*ptr1;//用來指像素行的指標 int r,g,b;//rgb三原色 int grey=0; Graphics::TBitmap *Bmp=new Graphics::TBitmap(); //Graphics::TBitmap *TemBmp=new Graphics::TBitmap(); Bmp->PixelFormat=pf24bit; Image1->Picture->Bitmap->PixelFormat = pf24bit; //Image1->Picture->Assign(Bmp); Bmp->Assign(Image1->Picture->Bitmap); int w = Bmp->Width; //取得高寬 int h = Bmp->Height; // //capEditCopy(cap1); //if(Clipboard()->HasFormat(CF_DIB)) //{ // Bmp->Assign(Clipboard()); //} for(int d = 0; d < h ; d ) { ptr =(Byte *) Bmp->ScanLine[d];//該行像素位址給ptr for(int c = 0; c < w; c ) { b=ptr[c*3]; //該點第一個位子是藍色 g=ptr[c*3 1]; //該點第二個位子是綠色 r=ptr[c*3 2]; //該點第三個位子是紅色 grey=(b g r)/3; //取灰階 if (grey>128) grey=255; //二值化 else grey=0; ptr[c*3]=(Byte)grey; //存回bgr值 ptr[c*3 1]=(Byte)grey; ptr[c*3 2]=(Byte)grey; } } //Image1->Picture->Bitmap=Bmp; Image1->Picture->Assign(Bmp); delete Bmp; } [/code] 問題點: 1.Height跟Width沒有給值 2.Image1->Picture->Assign(Bmp); Bmp的圖給Image1,但此時Bmp沒有東西呀! 你是要把Image1給Bmp吧! 應改成如下: Bmp->Assign(Image1->Picture->Bitmap); 3.Image1->Picture->Bitmap=Bmp; 這樣也不對! Image1->Picture->Assign(Bmp); 重寫程式如下: [code cpp] void __fastcall TForm1::N6Click(TObject *Sender) { Byte *ptr;//用來指像素行的指標 int grey,row,col,index; int w = Image1->Picture->Bitmap->Width; int h = Image1->Picture->Bitmap->Height; Image1->Picture->Bitmap->PixelFormat = pf24bit; for (row=0; row ptr = (Byte *) Image1->Picture->Bitmap->ScanLine[row]; //讀取列 Index = 0; for (col=0; col grey = (Byte) (0.30*ptr[index 2] 0.59*ptr[index 1] 0.11*ptr[index]); if (grey>128) grey=255; else grey=0; //二值化 ptr[index]=ptr[index 1]=ptr[index 2] = grey; index = 3; } } } [/code] 參考資料: http://www.eel.tsint.edu.tw/teacher/ttsu/物件導向程式設計/ch16.ppt 視窗程式設計與應用 -進階視窗繪圖與影像處理 p37~38 http://140.129.118.16/~richwang/BitmapAbout.pdf BCB的TBitmap的屬性說明 阿信~ |
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
我給他測試後好像問題出在指標沒正確指到Bmp
所以沒有改到值 再找看看...... 樓上那位大大好像不是錯在寬和高......
------
恩...
編輯記錄
istillloving 重新編輯於 2009-11-19 14:48:39, 註解 無‧
|
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
我把程式改成這樣是可以跑
但是有指標好像弄錯了 可能跳了一些位子了 Form1->Image1->Canvas->Pixels[i][j]=TColor(RGB(grey,grey,grey)); [code cpp] Byte *ptr,*ptr1;//用來指像素行的指標 int grey=0; Bmp->PixelFormat=pf24bit; capEditCopy(cap1); if(Clipboard()->HasFormat(CF_DIB)) { Bmp->Assign(Clipboard()); int h= Bmp->Height; int w= Bmp->Width; for(j = 0; j ptr =(Byte *)Bmp->ScanLine[j]; //該行像素位址給ptr for(i = 0; i grey = (ptr[i*3]*28 ptr[i*3 1]*151 ptr[i*3 2]*77)/256;; ptr[i*3]=(Byte)grey; //存回bgr值 ptr[i*3 1]=(Byte)grey; ptr[i*3 2]=(Byte)grey; Form1->Image1->Canvas->Pixels[i][j]=TColor(RGB(grey,grey,grey)); } } //Image1->Picture->Assign(Bmp); } [/code]
------
恩... |
senso
高階會員 發表:5 回覆:126 積分:226 註冊:2003-11-27 發送簡訊給我 |
我沒有webcam,用#8的code註解掉幾個地方,和直接拉image2圖進來加設PF,其他除了排版都沒改,
結果是除了白色(255,255,255),其他顏色都會變黑色,看起來很正常(如果你要的是這樣子的話)。 可以描述一下您說的取像確無法將圖片二值化或怎麼個不行嗎? 感覺上問題是沒有載入圖? [code cpp] { Byte *ptr,*ptr1;//用來指像素行的指標 int r,g,b;//rgb三原色 int grey=0; Graphics::TBitmap *Bmp=new Graphics::TBitmap(); //Graphics::TBitmap *TemBmp=new Graphics::TBitmap(); //Bmp->PixelFormat=pf24bit; //Image1->Picture->Assign(Bmp); //capEditCopy(cap1); //if(Clipboard()->HasFormat(CF_DIB)) if(1) { //Bmp->Assign(Clipboard()); Bmp->Assign(Image2->Picture->Bitmap); //我沒有webcam,所以直接拉image2圖進來 Bmp->PixelFormat=pf24bit; Image1->Picture->Assign(Bmp); } for(int d = 0; d { ptr =(Byte *)Bmp->ScanLine[d]; //該行像素位址給ptr for(int c = 0; c { b=ptr[c*3]; //該點第一個位子是藍色 g=ptr[c*3 1]; //該點第二個位子是綠色 r=ptr[c*3 2]; //該點第三個位子是紅色 if((b==255&&g==255&&r==255)) //如果是白色維持原來若不是變成黑色 grey=255; //0:代表black 255:代表白 else grey=0; ptr[c*3]=(Byte)grey; //存回bgr值 ptr[c*3 1]=(Byte)grey; ptr[c*3 2]=(Byte)grey; } } Image1->Picture->Bitmap=Bmp; delete Bmp; } [/code] 忘了在哪篇看到的 Image1->Picture->Bitmap=Bmp; 其效果等於 Image1->Picture->Assign(Bmp); 是可行的! |
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
一開始我的看法是認為
Bmp和Webcam是一個動態聯結 所以當雙for迴圈對Bmp做完運算後 底下輸出的Bmp是已經又被更新過了 Image1->Picture->Assign(Bmp); 所以永遠沒有辦法顯示運算過後的影像 於是我在雙for迴圈運算之前又新增了另外一組 Graphics::TBitmap *TBmp=new Graphics::TBitmap(); 我先令 TBmp = Bmp 那這樣TBmp就不會因為Bmp是動態的關係而一直更新 但是運算過後輸出TBmp還是一樣沒變 Image1->Picture->Assign(TBmp); 於是我又測試了這樣的寫法 [code cpp] int h= Bmp->Height; int w= Bmp->Width; TBmp->Height=h; TBmp->Width =w; for(j=0;j for(i=0;i TBmp->Canvas->Pixels[i][j]=Bmp->Canvas->Pixels[i][j]; } } [/code] 接著再對 TBmp 做運算後顯示出來 Image1->Picture->Assign(TBmp); 結果是可行的有改到值 所以我做了以下的猜測 Assign 這個語法是call by address 而不是 call by value 而 TBmp=Bmp 我想也是 call by address Bmp取得Webcam的畫面也是動態更新 看了一下函式 virtual void __fastcall Assign(Classes::TPersistent* Source); 他的確只傳位子
------
恩...
編輯記錄
istillloving 重新編輯於 2009-11-20 11:34:53, 註解 無‧
istillloving 重新編輯於 2009-11-20 11:36:20, 註解 無‧ istillloving 重新編輯於 2009-11-20 11:42:49, 註解 無‧ |
senso
高階會員 發表:5 回覆:126 積分:226 註冊:2003-11-27 發送簡訊給我 |
我怎麼覺得樓上TBmp = Bmp說的看起來怪怪的
應該是下面這樣才對吧 [code cpp] Graphics::TBitmap *Bmp=new Graphics::TBitmap(); Graphics::TBitmap *TBmp=new Graphics::TBitmap(); Bmp->Assign(...); //Bmp會產生另一份圖檔,原圖被改時Bmp不會有影響,是兩個則是各自的圖 TBmp=Bmp; //TBmp指向Bmp,TBmp和Bmp共用同一張圖 Image1->Picture->Assign(Bmp); //Image1->Picture->Bitmap和Bmp這兩個則是各自的圖 Image1->Picture->Bitmap=Bmp; //效果同assign /* 中間對Bmp修改 */ /* Image1->Picture->Bitmap不會變 */ Image1->Picture->Assign(TBmp); //因為TBmp和Bmp共用同一張圖,所以Image1->Picture->Bitmap會和Bmp一樣 delete Bmp,TBmp; [/code] 他在Bmp->Assign(Clipboard());的時候 Bmp就已經是獨立的一張圖了,不會再被webcam影響 |
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
所以你的看法是 Assign 這語法不是用call by address
說真的我在用WebCam的時候是使用 一點一點 慢慢存入Buff 的 沒遇到這個問題過 這算是新體驗...... ===================引 用 senso 文 章=================== 我怎麼覺得樓上TBmp = Bmp說的看起來怪怪的 應該是下面這樣才對吧 [code cpp] Graphics::TBitmap *Bmp=new Graphics::TBitmap(); Graphics::TBitmap *TBmp=new Graphics::TBitmap(); Bmp->Assign(...); //Bmp會產生另一份圖檔,原圖被改時Bmp不會有影響,是兩個則是各自的圖 TBmp=Bmp; //TBmp指向Bmp,TBmp和Bmp共用同一張圖 Image1->Picture->Assign(Bmp); //Image1->Picture->Bitmap和Bmp這兩個則是各自的圖 Image1->Picture->Bitmap=Bmp; //效果同assign /* 中間對Bmp修改 */ /* Image1->Picture->Bitmap不會變 */ Image1->Picture->Assign(TBmp); //因為TBmp和Bmp共用同一張圖,所以Image1->Picture->Bitmap會和Bmp一樣 delete Bmp,TBmp; [/code] 他在Bmp->Assign(Clipboard());的時候 Bmp就已經是獨立的一張圖了,不會再被webcam影響
------
恩...
編輯記錄
istillloving 重新編輯於 2009-11-20 15:42:08, 註解 無‧
|
senso
高階會員 發表:5 回覆:126 積分:226 註冊:2003-11-27 發送簡訊給我 |
Assign是call by address,但請看清楚說明...
TBitmap::Assign Copies a new bitmap image to the bitmap object. 給這個bitmap 一個新的bitmap 副本 virtual void __fastcall Assign(Classes::TPersistent* Source); Description Assign copies the bitmap image contained in Source to the bitmap object. Assign then calls the parent class's Assign. If the bitmap needs to be changed, the actual bitmap image is copied before the changes are made (copy on write). 另外Image1->Picture->Bitmap=Bmp;效果同assgin 請參考 http://delphi.ktop.com.tw/board.php?cid=168&fid=912&tid=58068 中的#3 簡單的說,Picture->Bitmap不是單純的一個指標成員而是一個property, Picture->Bitmap在read和write時有呼叫內建的一些方法 write=SetBitmap, 而SetBitmap呼叫SetGraphic(Value); 而SetGraphic中又用到assign ===================引 用 istillloving 文 章=================== 所以你的看法是 Assign 這語法不是用call by address
編輯記錄
senso 重新編輯於 2009-11-20 16:04:28, 註解 無‧
|
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
剛剛去看了一下說明的確是這樣
但是為什麼就是出不來...... ===================引 用 senso 文 章=================== Assign是call by address,但請看清楚說明... TBitmap::Assign Copies a new bitmap image to the bitmap object. 給這個bitmap 一個新的bitmap 副本 virtual void __fastcall Assign(Classes::TPersistent* Source); Description Assign copies the bitmap image contained in Source to the bitmap object. Assign then calls the parent class's Assign. If the bitmap needs to be changed, the actual bitmap image is copied before the changes are made (copy on write). 另外Image1->Picture->Bitmap=Bmp;效果同assgin 請參考 http://delphi.ktop.com.tw/board.php?cid=168&fid=912&tid=58068中的#3 簡單的說,Picture->Bitmap不是單純的一個指標成員而是一個property, Picture->Bitmap在read和write時有呼叫內建的一些方法 write=SetBitmap, 而SetBitmap呼叫SetGraphic(Value); 而SetGraphic中又用到assign ===================引 用 istillloving 文 章=================== 所以你的看法是 Assign 這語法不是用call by address
------
恩... |
istillloving
高階會員 發表:33 回覆:182 積分:183 註冊:2008-10-09 發送簡訊給我 |
我好像找到問題錯在哪了
但是我不知道原因是啥 首先你的 include 中的 [code cpp] #include [/code] 請把它改成 [code cpp] #include [/code] 接著我寫了一個新的 Button 可以正常的將影像轉成灰階了 [code cpp] Byte *ptr,*ptr1; int grey=0; capGrabFrameNoStop(cap1); capEditCopy(cap1); Bmp->Assign(Clipboard()); Bmp->PixelFormat=pf24bit; int h= Bmp->Height; int w= Bmp->Width; for(j = 0; j ptr =(Byte *)Bmp->ScanLine[j]; //該行像素位址給ptr for(i = 0; i grey = (ptr[i*3]*28 ptr[i*3 1]*151 ptr[i*3 2]*77)/256; ptr[i*3] = ptr[i*3 1] = ptr[i*3 2] = (Byte)grey; //Form1->Image1->Canvas->Pixels[i][j]=TColor(RGB(grey,grey,grey)); } } Image1->Picture->Assign(Bmp); [/code]
------
恩...
編輯記錄
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |