赤色領域を検出(2)
前の方法だと光、影、カメラの種類などの環境変化に弱かったので、もっと相対的に赤を検出する。
cvDiv()という2つの画像の全ピクセルの商を一発で求める関数があるので、「赤の要素が青・緑それぞれの1.5倍あり、さらに赤が100以上の値のピクセル」を赤とみなして抜き出す
// 赤の要素が100以上で、緑と青より1.5倍以上あるピクセルを抽出 cvThreshold(imgR, imgThreshold_R, 100, 255, CV_THRESH_BINARY); cvDiv(imgR, imgG, imgTmp, 10); // 10倍 cvThreshold(imgTmp, imgThreshold_G, 15, 255, CV_THRESH_BINARY); cvDiv(imgR, imgB, imgTmp, 10); cvThreshold(imgTmp, imgThreshold_B, 15, 255, CV_THRESH_BINARY); cvAnd(imgThreshold_G, imgThreshold_B, imgTmp, NULL); cvAnd(imgTmp, imgThreshold_R, imgResult, NULL);
気になること
- cvDivは、ゼロ除算されたらどうなるのか?
- cvDivの第四引数scaleを10にしているので、最大値は2550になる事があるだろうけど、IplImageの深さはIPL_DEPTH_8Uで足りてるのか。とりあえず動いてはいる。試しにIPL_DEPTH_16Uにしたら実行時にバッファあふれて即死する。
colortrack.cpp
#include <stdio.h> #include <highgui.h> #include <cv.h> IplImage *img = NULL; IplImage *imgR, *imgG, *imgB, *imgThreshold_R, *imgThreshold_G, *imgThreshold_B, *imgResult, *imgTmp; void onMouse(int event, int x, int y, int flags, void* param){ printf("x:%d y:%d r:%d g:%d b:%d %s", x, y, // マウス座標とRGBを出力 (unsigned char)imgR->imageDataOrigin[x+y*imgR->width], (unsigned char)imgG->imageDataOrigin[x+y*imgG->width], (unsigned char)imgB->imageDataOrigin[x+y*imgB->width], "\n"); } int main(int argc, char** argv) { bool isStop = false; CvCapture *capture = NULL; capture = cvCreateCameraCapture(0); //capture = cvCaptureFromAVI("test.avi"); if(capture == NULL){ printf("capture device not found!!"); return -1; } img = cvQueryFrame(capture); const int w = img->width; const int h = img->height; imgR = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgG = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgB = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgThreshold_R = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgThreshold_G = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgThreshold_B = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgResult = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); imgTmp = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1); char winNameCapture[] = "Capture"; char winNameResult[] = "Result"; cvNamedWindow(winNameCapture, CV_WINDOW_AUTOSIZE); cvNamedWindow(winNameResult, CV_WINDOW_AUTOSIZE); cvSetMouseCallback(winNameCapture, onMouse, 0); cvSetMouseCallback(winNameResult, onMouse, 0); int waitKey; while (1) { if(!isStop){ if((img = cvQueryFrame(capture)) == NULL) break; cvSplit(img, imgB, imgG, imgR, NULL); // BGRを分解 // 赤の要素が100以上で、緑と青より1.5倍以上あるピクセルを抽出 cvThreshold(imgR, imgThreshold_R, 100, 255, CV_THRESH_BINARY); cvDiv(imgR, imgG, imgTmp, 10); // 10倍 cvThreshold(imgTmp, imgThreshold_G, 15, 255, CV_THRESH_BINARY); cvDiv(imgR, imgB, imgTmp, 10); cvThreshold(imgTmp, imgThreshold_B, 15, 255, CV_THRESH_BINARY); cvAnd(imgThreshold_G, imgThreshold_B, imgTmp, NULL); cvAnd(imgTmp, imgThreshold_R, imgResult, NULL); cvShowImage(winNameCapture, img); cvShowImage(winNameResult, imgResult); } waitKey = cvWaitKey(33); if(waitKey == 'q') break; if(waitKey == ' '){ isStop = !isStop; if(isStop) printf("stop\n"); else printf("start\n"); } } cvReleaseCapture(&capture); cvDestroyWindow(winNameCapture); cvDestroyWindow(winNameResult); return 0; }