OpenCV の C のソースを Python に変換するときのメモ。
C にしておくと、ソースとオブジェクトの二つのファイルの管理が必要となったり、ライブラリの置く場所など、いろいろめんどう。
というわけで、Python にしてしまおうという計画。
言語文法上で注意するのはこれくらい?
- C の文は「;」で終了するが、Python にはない。
- C の変数宣言では型が必要だが、Python は変数名だけ。
- C では「&」をつけて、その変数のポインタを求めたりするが、Python では不要。
- True/False や Not の表記
- nil や NULL や None の表記
- Python のインデント。
「import cv」とすると、メソッド名などに「cv.」をつけることになる。
しかし、cv. の後のメソッド名には「cv」がつかない。
ただし、定数名の頭についている「CV」はそのまま残る。
こんな感じ。
C:
frame = cvQueryFrame(capture);
cvSmooth(frame, frame, CV_GAUSSIAN, 3, 3);
Python:
frame = cv.QueryFrame(capture)
cv.Smooth(frame, frame, cv.CV_GAUSSIAN, 3, 3)
C の cvQueryFrame は Python では cv.QueryFrame となる。
ただし定数は、C で CV_GAUSSIAN、Python で cv.CV_GAUSSIAN となる。
厄介なのがマクロ(?)。Python にはない。ふつーにタプルで表現したりする。
C:
const int w = frame->width;
const int h = frame->height;
imgR = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, 1);
cvCircle(frame, cvPoint(gX, gY), 80, CV_RGB(0,0,255), 6, 8, 0);
Python:
the_size = cv.GetSize(frame)
imgR = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
cv.Circle(frame, (gX, gY), 80, (0, 0, 255), 6, 8, 0)
そのほか、調べないとわからないもの。
C:
cvMoments(imgResult, &moments, 0);
double m00 = cvGetSpatialMoment(&moments, 0, 0);
Python:
moments = cv.Moments(cv.GetMat(imgResult, 1), 0)
m00 = cv.GetSpatialMoment(moments, 0, 0)
サンプルとして、次のページにあった赤い色のエリアを抽出し、重心を求めるソースの C 版と Python 版を示す。
http://d.hatena.ne.jp/shokai/20090203/1233609981
http://opencv-srf.blogspot.ro/2010/09/object-detection-using-color-seperation.html
これは Mac (10.9.1 Mavericks) と Raspberry Pi で動作確認した。
C:
#include <opencv/cv.h>
#include <opencv/highgui.h>
// This function threshold the HSV image and create a binary image
IplImage* GetThresholdedImage(IplImage* imgHSV) {
IplImage* imgResult = cvCreateImage(cvGetSize(imgHSV), IPL_DEPTH_8U, 1);
cvInRangeS(imgHSV, cvScalar(150, 160, 60), cvScalar(200, 256, 256), imgResult);
return imgResult;
}
int main() {
CvCapture* capture = NULL;
IplImage *frame = NULL;
IplImage *imgR = NULL, *imgG = NULL, *imgB = NULL;
IplImage *imgThreshold_R = NULL, *imgThreshold_G = NULL, *imgThreshold_B = NULL;
IplImage *imgTmp = NULL;
IplImage *imgHSV = NULL;
IplImage *imgResult = NULL;
CvMoments moments;
capture = cvCaptureFromCAM(0);
if (!capture) {
printf("Capture failure\n");
return -1;
}
cvNamedWindow("Video");
cvNamedWindow("Results");
// iterate through each frames of the video
while (true) {
frame = cvQueryFrame(capture);
if (!frame) {
break;
}
frame = cvCloneImage(frame);
cvSmooth(frame, frame, CV_GAUSSIAN, 3, 3); // smooth the original image using Gaussian kernel
if (1) {
const int w = frame->width;
const int h = frame->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);
cvSplit(frame, 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);
cvMoments(imgResult, &moments, 0);
double m00 = cvGetSpatialMoment(&moments, 0, 0);
double m10 = cvGetSpatialMoment(&moments, 1, 0);
double m01 = cvGetSpatialMoment(&moments, 0, 1);
int gX = m10 / m00;
int gY = m01 / m00;
cvCircle(frame, cvPoint(gX, gY), 80, CV_RGB(0,0,255), 6, 8, 0);
} else {
imgHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
cvCvtColor(frame, imgHSV, CV_BGR2HSV); // Change the color format from BGR to HSV
imgResult = GetThresholdedImage(imgHSV);
cvSmooth(imgResult, imgResult, CV_GAUSSIAN, 3, 3); // smooth the binary image using Gaussian kernel
}
cvShowImage("Results", imgResult);
cvShowImage("Video", frame);
// Clean up used images
cvReleaseImage(&imgHSV);
cvReleaseImage(&imgResult);
cvReleaseImage(&frame);
// Wait 50mS
int c = cvWaitKey(10);
// If 'ESC' is pressed, break the loop
if ((char)c == 0x1b ) {
break;
}
}
cvDestroyAllWindows() ;
cvReleaseCapture(&capture);
return 0;
}
Python:
#!/usr/bin/env python
# coding: UTF-8
"""
DetectingRedObjects.py
"""
import cv
def GetThresholdedImage(imgHSV):
imgResult = cv.CreateImage(cv.GetSize(imgHSV), cv.IPL_DEPTH_8U, 1)
cv.InRangeS(imgHSV, cv.Scalar(150, 160, 60), cv.Scalar(200, 256, 256), imgResult)
return imgResult
def main():
capture = None
frame = None
imgR = imgG = imgB = None
imgThreshold_R = imgThreshold_G = imgThreshold_B = None
imgTmp = imgHSV = imgResult = None
moments = None
capture = cv.CaptureFromCAM(0)
if (not capture):
print("Capture failure")
return -1
cv.NamedWindow("Video")
cv.NamedWindow("Results")
# iterate through each frames of the video
while (True):
frame = cv.QueryFrame(capture)
if (not frame):
break;
frame = cv.CloneImage(frame)
cv.Smooth(frame, frame, cv.CV_GAUSSIAN, 3, 3) # smooth the original image using Gaussian kernel
if (True):
# 赤色領域を検出(3) 重心も計算
# http://d.hatena.ne.jp/shokai/20090203/1233609981
the_size = cv.GetSize(frame)
# w = frame.width
# h = frame.height
imgR = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgG = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgB = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgThreshold_R = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgThreshold_G = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgThreshold_B = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgResult = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
imgTmp = cv.CreateImage(the_size, cv.IPL_DEPTH_8U, 1)
cv.Split(frame, imgB, imgG, imgR, None) # BGRを分解
# 赤の要素が100以上で、緑と青より1.5倍以上あるピクセルを抽出
cv.Threshold(imgR, imgThreshold_R, 100, 255, cv.CV_THRESH_BINARY)
cv.Div(imgR, imgG, imgTmp, 10) # 10倍
cv.Threshold(imgTmp, imgThreshold_G, 15, 255, cv.CV_THRESH_BINARY)
cv.Div(imgR, imgB, imgTmp, 10)
cv.Threshold(imgTmp, imgThreshold_B, 15, 255, cv.CV_THRESH_BINARY)
cv.And(imgThreshold_G, imgThreshold_B, imgTmp, None)
cv.And(imgTmp, imgThreshold_R, imgResult, None)
# cv.Moments(imgResult, moments, 0)
moments = cv.Moments(cv.GetMat(imgResult, 1), 0)
m00 = cv.GetSpatialMoment(moments, 0, 0)
m10 = cv.GetSpatialMoment(moments, 1, 0)
m01 = cv.GetSpatialMoment(moments, 0, 1)
if (m00 != 0):
gX = int(m10 // m00)
gY = int(m01 // m00)
# cvCircle(frame, cvPoint(gX, gY), 80, CV_RGB(0,0,255), 6, 8, 0);
cv.Circle(frame, (gX, gY), 80, (0, 0, 255), 6, 8, 0)
else:
# Color Detection & Object Tracking
# http://opencv-srf.blogspot.ro/2010/09/object-detection-using-color-seperation.html
imgHSV = cv.CreateImage(cv.GetSize(frame), cv.IPL_DEPTH_8U, 3)
cv.CvtColor(frame, imgHSV, cv.CV_BGR2HSV) # Change the color format from BGR to HSV
imgResult = GetThresholdedImage(imgHSV)
cv.Smooth(imgResult, imgResult, cv.CV_GAUSSIAN, 3, 3) # smooth the binary image using Gaussian kernel
cv.ShowImage("Results", imgResult)
cv.ShowImage("Video", frame)
# Clean up used images
# cv.ReleaseImage(imgHSV)
# cv.ReleaseImage(imgResult)
# cv.ReleaseImage(frame)
# Wait 50mS
c = cv.WaitKey(10)
# If 'ESC' is pressed, break the loop
if (c == 0x1b):
break
cv.DestroyAllWindows()
# cv.ReleaseCapture(capture)
return 0
if __name__ == '__main__':
main()