因為來源是二值影像,所以這邊想到一個更簡潔,效果我覺得一定好的方式 (自我感覺良好:P),整個過程分三步驟:
- 對影像做水平掃描,若像素 A 的左或右為背景,則像素 A 為邊緣。
- 對影像做垂直掃描,若像素 A 的上或下為背景,則像素 A 為邊緣。
- 將步驟一得到的水平影像和步驟二的垂直影像做「logical OR operation」。
程式碼下載 (DFS is non-recursive version)
IplImage* iplImg = cvLoadImage("lena.jpg"); cv::Mat cvMatImg(iplImg, 0); cv::imshow("cv::Mat Show", cvMatImg);
IplImage iplImg2; iplImg2= IplImage(cvMatImg); cvShowImage("IplImage2 Show", &iplImg2);在第一個範例中,我們可以看到 cv::Mat 的建構子有兩個參數,比較重要的是第二個參數,如果設定成 0,代表不複製影像,也就是兩個變數的 row data 共用同個記憶體位置,header 則各自有。
inline Mat::operator IplImage() const { IplImage img; cvInitImageHeader(&img, size(), cvIplDepth(flags), channels()); cvSetData(&img, data, (int)step); return img; }
bool BrokenLineGraph(IplImage *blImg, int *data, int *range, int dataNum, bool reset);
bool HistogramGraph(IplImage *hgImg, int *data, int *range, int dataNum, bool reset, CvRNG *rng);
cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse);
cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param CV_DEFAULT(NULL));
void MouseCallback(int event, int x, int y, int flags);
void MouseCallback(int event, int x, int y, int flags, void *param);很明顯地,新版多了一個參數「void* param」,這樣一來,就可以傳入一個結構,來記錄滑鼠座標,毋須定義全域變數。另外,還有一個外表看不出來的差異,就是舊版(b3.1)取得的滑鼠座標需要上下顛倒,但新版不用,詳細可以看原始碼。
-baijuyi- [/home/Bachelor_91/linly/old] -13:48- ls
a.cc git
-baijuyi- [/home/Bachelor_91/linly/old] -13:48- cat a.cc
#include <iostream>
using namespace std;
int main()
{
a = 3;
}
-baijuyi- [/home/Bachelor_91/linly/new] -13:49- ls在兩個資料夾都有 a.cc 和 git,而 new 資料夾的 a.cc 檔案中,把 a = 3; 改成 b = 3;,現在要做 patch:
a.cc git
-baijuyi- [/home/Bachelor_91/linly/new] -13:49- cat a.cc
#include <iostream>
using namespace std;
int main()
{
b = 3;
}
-baijuyi- [/home/Bachelor_91/linly] -13:52- diff -ruN old/ new/ -x git > my.patch其中有一個參數:-x git,是省略這個檔案不比,有時候會有一些說明檔在裡頭,沒有必要去 patch 它。接著就是打 patch:
-baijuyi- [/home/Bachelor_91/linly] -13:53- cat my.patch
diff -ruN -x git old/a.cc new/a.cc
--- old/a.cc 2009-09-17 13:48:36.000000000 +0800
+++ new/a.cc 2009-09-17 13:48:04.000000000 +0800
@@ -4,5 +4,5 @@
int main()
{
- a = 3;
+ b = 3;
}
-baijuyi- [/home/Bachelor_91/linly] -13:59- patch -p0 < my.patch這樣就完成程式碼的更新了,如果說我到 old/ 這個資料夾打 patch 的話,由於是往下一層,所以要把 -p0 改成 -p1。最後,因為我的用 patch,它會幫我把原先的舊檔案,以原檔名加上 .orig,所以想把這些檔案都刪除的話,可以利用 find 去做:
-baijuyi- [/home/Bachelor_91/linly] -14:16- cat old/a.cc
using namespace std;
int main()
{
b = 3; // =>改變了
}
-baijuyi- [/home/Bachelor_91/linly] -14:03- ls old/
a.cc a.cc.orig git
-baijuyi- [/home/Bachelor_91/linly] -14:03- find . -name '*.orig' -exec rm -f {} ';'
-baijuyi- [/home/Bachelor_91/linly] -14:03- ls old/
a.cc git
CPU GPU
500x500 0.188 0.109
1000x1000 6.131 0.202
3000x3000 200.819 5.241
5000x5000 1222.182 12.480
如果你的筆記型電腦或者桌機的顯示卡不支援CUDA,那麼,cudaGetDeviceProperties 只能抓到一個虛擬裝置「device 0」,而該裝置內容如下:Y = 0.299*data[2] + 0.587*data[1] + 0.114*data[0];● Normal RGB
Cb = -0.1687*data[2] - 0.3312*data[1] + 0.5*data[0];
Cr = 0.5*data[2] - 0.4183*data[1] - 0.0816*data[0];
if(60 < Y && Y < 255)
{
if(-25 < Cb && Cb < 0)
{
if(10 < Cr && Cr < 45)
{
// skin
}
else
{
// non-skin
}
}
else
{
// non-skin
}
}
else
{
// non-skin
}
double r;
double g;
double b;
double F1;
double F2;
double w;
int size = 320*240;
Byte* data = (Byte*)scan0.ToPointer();
for(int i = 0; i < size; ++i, data += 3)
{
if(data[0] == 0 && data[1] == 0 && data[2] == 0)
{
r = g = b = 0;
}
else
{
r = (double)data[2]/(data[2]+data[1]+data[0]);
g = (double)data[1]/(data[2]+data[1]+data[0]);
}
F1 = -1.3767*r*r + 1.0743*r + 0.1452;
F2 = -0.776*r*r + 0.5601*r + 0.1766;
w = (r-0.33)*(r-0.33) + (g-0.33)*(g-0.33);
if((g < F1) && (g > F2) &&
(w > 0.0004) &&
(data[2] > data[1]) &&
(data[1] > data[0]) &&
(data[2] - data[1] >= 16))
{
// skin
}
else
{
// non-skin
}
}