<環境>
- Windows10 64bit
- visual studio 2017
- opencv 3.4.1
カメラからの円検出のプログラムと重心を求めるプログラムを合体させたいです。
ここで問題があるのですが、カメラからの映像をMat img = imread("sample.jpg", IMREAD_GRAYSCALE);で画像として取り出しグレースケール化してから重心を求めるプログラムのようにすればいいのでしょうか?
その方法で行うとしたらまずどのフォーマットで画像を取得するかを考えないとだめですね。
手順としてはカメラから円を検出して赤色で囲う、検出された円を画像として置き換え、重心を求める。
ただカメラからの映像から円の画像を作る?関数はopencvにあるでしょうか?
まず一つ目のプログラムはepistemeさんから頂いた重心を画像から求めるプログラム。
#include "opencv2/opencv.hpp" int main(){ using namespace cv; Mat img = imread("sample.jpg", IMREAD_GRAYSCALE); // unsigned char* img.data : 画像データの先頭 // int img.rows : 幅(pixel) // int img.cols : 高さ(pixel) // size_t img.step : 一行のbyte数 int count = 0; float x_g = 0.0f; float y_g = 0.0f; for ( int y = 0; y < img.rows; y++ ) { for ( int x = 0; x < img.cols; x++ ) { if ( img.data[y*img.step + x] == 255 ) { count++; x_g += x; y_g += y; } } } Point2f mc = Point2f( x_g/count, y_g/count); circle( img, mc, 4, Scalar(100), 2, 4); imshow("img",img); waitKey(0); }
二つ目は過去に作ったカメラの映像からハフ変換を利用して円を検出するプログラム。
#include <stdio.h> #include <opencv/cv.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgcodecs/imgcodecs.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> using namespace cv; int main(int argc, char* argv[]) { int i; float *p; double w = 320, h = 240; IplImage *src_img = 0, *gray_img = 0; CvMemStorage *storage; CvSeq *circles = 0; CvCapture *capture = 0; /* この設定は,利用するカメラに依存する */ capture = cvCreateCameraCapture(0); // (2)キャプチャサイズを設定する. cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, w); cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, h); cvNamedWindow("circles", CV_WINDOW_AUTOSIZE); while (1) { src_img = cvQueryFrame(capture); CvSize sizeOfImage = cvGetSize(src_img); //IplImage *gray_img = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1); gray_img = cvCreateImage(cvGetSize(src_img), IPL_DEPTH_8U, 1); // グレイスケールに変換 cvCvtColor(src_img, gray_img, CV_BGR2GRAY); //src_img_gray = cvQueryFrame (capture); // (2)ハフ変換のための前処理(画像の平滑化を行なわないと誤検出が発生しやすい) cvSmooth(gray_img, gray_img, CV_GAUSSIAN, 11, 11, 0, 0); storage = cvCreateMemStorage(0); // (3)ハフ変換による円の検出と検出した円の描画 circles = cvHoughCircles(gray_img, storage, CV_HOUGH_GRADIENT, 1, 100, 20, 50, 10, MAX(gray_img->width, gray_img->height)); for (i = 0; i < circles->total; i++) { p = (float *)cvGetSeqElem(circles, i); cvCircle(src_img, cvPoint(cvRound(p[0]), cvRound(p[1])), 3, CV_RGB(0, 255, 0), -1, 8, 0); cvCircle(src_img, cvPoint(cvRound(p[0]), cvRound(p[1])), cvRound(p[2]), CV_RGB(255, 0, 0), 3, 8, 0); } //↓この先に重心を求めるプログラムをぶち込む? int count = 0; double x_g = 0.0, y_g = 0.0; for (int y = 0; y < gray_img->width; y++) { for (int x = 0; x < gray_img->height; x++) { if (img.at<unsigned char>(y, x) == 255) { //img.atの扱う画素が何バイトかわからないためunsigned charを定義することで、unsigned chaによりimg.atの扱う画素が入るメモリが確保できた。 count++; x_g += x; y_g += y; } } } x_g /= count; y_g /= count; Point2f mc = Point2f(x_g, y_g); // (4)検出結果表示用のウィンドウを確保し表示する cvShowImage("circles", src_img); cvWaitKey(10); } cvDestroyWindow("circles"); cvReleaseImage(&src_img); cvReleaseImage(&gray_img); cvReleaseMemStorage(&storage); return 0; }
<編集6/17>質問の編集までに時間がかかりすいませんでした。
自身で解決できないか試行錯誤したのですがうまくいかず途方に暮れていました。
合体とは載せた二つのプログラム、「重心を画像から求めるプログラム」と「カメラの映像からハフ変換を利用して円を検出するプログラム」を組み合わせて、「カメラの映像からハフ変換を利用して円を検出した後、検出した円から重心を求めて、その重心の部分に赤い点を描画するプログラムを作る」ことを言っていました。
説明不足で本当にすいません。
お願い事のようになってしまい申し訳ないのですが、
今回の解決すべき問題点は円を検出するのに働く以下の部分、
circles = cvHoughCircles(gray_img, storage, CV_HOUGH_GRADIENT, 1, 100, 20, 50, 10, MAX(gray_img->width, gray_img->height));
から検出した円の面積というか画素の塊の情報を
int count = 0; float x_g = 0.0f; float y_g = 0.0f; for ( int y = 0; y < img.rows; y++ ) { for ( int x = 0; x < img.cols; x++ ) { if ( img.data[y*img.step + x] == 255 ) { count++; x_g += x; y_g += y; } } } Point2f mc = Point2f( x_g/count, y_g/count);
に入力して重心を求められるのではないかと考えているのですが、解決法はわかるのですが、書き方がわかりません。
どのように「書き方」を調べればいいのでしょうか?
いつも皆様に解決してもらっているばかりで自分ではなにもできていません。というよりうまく学習できていません。
回答1件
あなたの回答
tips
プレビュー