Mõtlesin, et üle pika aja testin võrratu OpenCV (2.4 ja VC9) võimalusi ja natuke ka meenutan C++, mida kahjuks igapäevaselt ei kasuta. Võtsin eesmärgi teha nö lihtsa prototüübi, mis suudaks leida pildilt palgi(d). Mingi sarnane rakendus vist kunagi võitis Ajujahi.
Üldiselt algoritm lihtne ja seda saab aina rohkem täiustada. Antud kood leiab “ümmargused” asjad, olgu see lillepott, coca cola purk või loeb ümmargused ehted kuusel kokku.
Parima tulemuse saab loomulikult, kui objekti on suht otse pildistatud.
Soovitav täiustus algoritmi, et võrreldaks ringi suurust tervikpildi suurusega. Et ring poleks liiga pisike ja liiga suur. Seda saab edukalt teostada funktsiooni HoughCircles kahe viimase parameetriga.
Lõikame leitud ringi fragmendi välja ja küsime keskmise värvuse. Te saate algoritmi täiustada, kui võtate ringist kaks fragmenti. Siis saate täpsema keskmise värvuse, mina hetkel võtan vaid ühe.
win32 binary saab alla laadida siit
Programmi väljakutse “circle.exe linkpildile”
Koodifragmendi panen seekord siia:
#include “stdafx.h”
#include <iostream>
#include “cv.h”
#include “highgui.h”#include “cxcore.h”
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
#include <cmath>
#include <vector>
#include <algorithm>#include “opencv.hpp”
#include <string>using namespace cv;
using namespace std;int ColorAsRGB(int Red, int Green, int Blue)
{
return (Red*65536)+(Green*256)+Blue;
}int _tmain(int argc, _TCHAR* argv[])
{
std::string fname = argc >= 2 ? argv[1] : “test.jpg”;
cv::Mat src = cv::imread(fname);cv::Mat pdest;
cv::Mat gray;// selle kohaga olge ettevaatlik; järsku peaks pildi veel väiksemaks teisendama
cv::resize(src, pdest, Size(1024, 768), 0, 0, INTER_CUBIC);
cv::cvtColor(pdest, gray, CV_BGR2GRAY);GaussianBlur( gray, gray, cv::Size(9, 9), 2, 2 );
vector<Vec3f> circles;
HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 2, gray.rows/4, 200, 100);
if (circles.size() < 1)
HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 1, gray.rows/8, 200, 20, 35, 0);// debug
std::cout << circles.size() <<std::endl;
for( size_t i = 0; i < circles.size(); i++ )
{Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
// —
int radius = cvRound(circles[i][2]);int x = cvRound(circles[i][0]);
int y = cvRound(circles[i][1]);
int delta = 5;Point tlc( x-(radius+delta),y-(radius+delta));
Point brc( x+(radius+delta),y+(radius+delta));Rect roi_rect(brc, tlc);
// lõikame regiooni välja keskmise värvuse jaoks
IplImage iplimg = pdest;
cvSetImageROI(&iplimg,roi_rect);Mat roiimg = cvarrToMat(&iplimg);
cvResetImageROI(&iplimg);// mis värv seal ikka siis rohkem domineerib
cv::Scalar rgbcolavg =cv::mean(roiimg);int rgbval = ColorAsRGB(rgbcolavg[2],rgbcolavg[1], rgbcolavg[0]);
// Teoreetiline PUIDU värvus; värske männipuit ntx
// Soovitan seda väärtus tweakida, siis tuvastus täpsem;
// See on lihtsalt int muutuja koos RGB väärtustega
if ((rgbval >= 11704411) && (rgbval <= 16048566))
{// joonistame ristküliku ümber
cv::rectangle( pdest,tlc,brc,Scalar( 0, 255, 255 ),1,8 );// joonistame leitud “ringile” ringi ümber
circle( pdest, center, 3, Scalar(0,255,0), -1, 8, 0 );// joonistame leitud ringile keskpunkti
circle( pdest, center, radius, Scalar(0,0,255), 3, 8, 0 );// kuvame siis leitu
stringstream ss;
ss << “leitudRing ” << i;
string caption = ss.str();cv::imshow(caption, pdest);
// väike debug
printf(“%.0f/%.0f/%.0f %d”, rgbcolavg[0], rgbcolavg[1], rgbcolavg[2], rgbval);
printf(” %d \n”,radius);}
}cv::waitKey(0);
return 0;
}
Lisa kommentaar