שלום, אני מנסה לכתוב תוכנה ב C++ שלפי ניתוח תמונה תמצא קו שחור ותעקוב אחריו.
הדרישות הן יחסית פשוטות, דוע שהקו בגודל מסויים והרקע נמצא בקונטרסט מספיק גדול ממנו כדי שייעלם על ידי פעולת threshold פשוטה. הבעיה שלי היא שאובייקטים אחרים לא עוברים את ה thershold ונמצאים בתמונה.
מותר לי להניח כי האובייקט הכי גדול הוא הקו ולכן אני מנסה לכתוב תוכנה שתמצא את האובייקט הכי גדול ותמחק את כל השאר.
חשוב להגיד שאני עובד במערת הפעלה Ubuntu 10.10 וכותב את הקוד בתוכנה Eclipse
עם ה g++ קומפיילר. אני משתמש בספרייות ה openCv.
ניסיתי עד כה 2 שיטות:
1) שימוש בפונקציית mybwlabel שנכתבה על ידי shekmantang ונמצאת בקישור:http://minds.nuim.ie/~shekmantang/opencv-bwlabel/
שילבתי את זה עם תוכנה שלוקחת על פריים ומבצעת עלי פעולת thershold. להלן הקוד:
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <ctime>
#include <vector>
#include <map>
using namespace std;
int myLabel(IplImage* I,vector<CvPoint>* regions);
int main(){
CvCapture* capture = cvCaptureFromCAM( 0 );//choose the webcam
IplImage* frame;
IplImage* gauss;
IplImage* gray;
IplImage* thersh;
IplImage* labelled_img;
double diff;
clock_t start;
vector<CvPoint>* R=new vector<CvPoint>[20];
int numOfLabels;
uchar* Lpixel;
if ( !capture ) {
fprintf( stderr, "ERROR: capture is NULL \n" );
getchar();
return -1;
}
cvNamedWindow( "mywindow", CV_WINDOW_AUTOSIZE );//create window
while ( 1 ) {
start = std::clock(); //TIMING START
frame = cvQueryFrame( capture );//capture single frame from camera
if ( !frame ) {
fprintf( stderr, "ERROR: frame is null.\n" );
getchar();
break;
}
//actual image processing starts here
gray = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );
cvCvtColor( frame, gray, CV_BGR2GRAY );//converting to grayscale
gauss = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
cvSmooth( gray, gauss, CV_GAUSSIAN, 3, 3 );//Gaussian filter
trash=cvCreateImage(cvGetSize(gauss),IPL_DEPTH_8U, 1);
cvThreshold(gauss,thersh,100,255,CV_THRESH_BINARY) ;
numOfLabels=myLabel(thersh,R);
labelled_img=cvCreateImage(cvGetSize(thersh),IPL_D EPTH_8U,1);
//Example of use: randomly color on each region
int i,l,h,w,size,biggest_obj;
size=0;
biggest_obj=0;
Lpixel=(uchar*)labelled_img->imageData;
for(l=0;l<numOfLabels;l++)
if(R[l].size()>size)
{
biggest_obj=l;
size=R[l].size();
}
for(l=0;l<numOfLabels;l++)
{
for(i=0;i<R[l].size();i++)
{
h=R[l].at(i).x;
w=R[l].at(i).y;
Lpixel[h*labelled_img->widthStep+w]=0;
}
}
for(i=0;i<R[biggest_obj].size();i++)
{
h=R[biggest_obj].at(i).x;
w=R[biggest_obj].at(i).y;
Lpixel[h*labelled_img->widthStep+w]=255;
}
diff = ( clock() - start ) / (double)CLOCKS_PER_SEC; //STOP TIMING
printf("TIME: %f\n",diff);
cvShowImage( "mywindow", labelled_img );//show res
if ( (cvWaitKey(10) & 255) == 27 ) break;//exit loop is esc key is pressed
}
// Releases
cvReleaseCapture(&capture);
cvDestroyWindow("mywindow");
cvReleaseImage(&frame);
cvReleaseImage(&gauss);
cvReleaseImage(&gray);
cvReleaseImage(&trash);
cvReleaseImage(&labelled_img);
return 0;
}
int myLabel(IplImage* I,vector<CvPoint>* regions){
int height = I->height;
int width = I->width;
int i,j;
uchar *pixel;
CvMat* L=cvCreateMat(height,width,CV_32FC1);
int up,left;
int label=1;
int count=0;
map<int,int> eqvTable;
pixel=(uchar*)I->imageData;
int lowest=-1;
//-----------------LABEL THE PIXELS
for(i=0;i<height;i++){
for(j=0;j<width;j++){
if(pixel[i*I->widthStep+j]==255){
up=(i==0)?0:cvmGet(L,i-1,j); //avoiding array out of bound indexing error
left=(j==0)?0:cvmGet(L,i,j-1);
//printf("(%d,%d) -> %d , %d\n",i,j,up,left);
if(up==0 && left!=0){
cvmSet(L,i,j,left);
}
if(up!=0 && left==0){
cvmSet(L,i,j,up);
}
if(up!=0 && left!=0){
cvmSet(L,i,j,up);
if(up!=left){
eqvTable.insert(make_pair(left,up));
}
}
else if(up==0 && left==0){
label++;
cvmSet(L,i,j,label);
}
}
}
}
//-----------------
//-----------------FIX THE TABLE
int last;
int prev_last,label_count=0;
map<int,int> unique_labels;
map<int,int>::iterator ul_iter;
map<int,int>::iterator sec_iter;
for( map<int,int>::iterator iter = eqvTable.begin(); iter != eqvTable.end(); ++iter ) {
//printf("%d -> %d\n",(*iter).first,(*iter).second);
last=(*iter).second;
sec_iter=eqvTable.find((*iter).second);
while(sec_iter!=eqvTable.end()){
last=(*sec_iter).second;
//printf("____ %d -> %d\n",(*sec_iter).first,(*sec_iter).second);
sec_iter=eqvTable.find((*sec_iter).second);
}
if(prev_last!=last){
prev_last=last;
ul_iter=unique_labels.find(last);
if(ul_iter==unique_labels.end()){
label_count++;
unique_labels.insert(make_pair(last,label_count));
}
}
(*iter).second=last;
}
//-----------------
//-----------------UPDATE THE LABEL MATRIX
int temp;
CvPoint pt;
vector<CvPoint> blobs[label_count];
for(i=0;i<L->height;i++){
for(j=0;j<L->width;j++){
temp=cvmGet(L,i,j);
if(temp!=0){
sec_iter=eqvTable.find(temp);
if(sec_iter!=eqvTable.end()){
//ul_iter=unique_labels.find((*sec_iter).second);
cvmSet(L,i,j,(*sec_iter).second);
}
}
}
}
//----------------STORE info to "regions"
for(i=0;i<height;i++){
for(j=0;j<width;j++){
temp=cvmGet(L,i,j);
if(temp!=0){
pt.x=i;
pt.y=j;
ul_iter=unique_labels.find(temp); //[2,17,15] -map-> [1,2,3]
temp=(*ul_iter).second;
regions[temp-1].push_back(pt);
}
}
}
return label_count;
}
אך זה לא עובד ואני לא מבין למה.
שיטה שנייה הייתה לקבל חזרה את הקונטורים של האובייקטים בעזרת cvfindcontuor ואז לתחום במלבנים את קונטורים, המלבן בעל השטח הכי גדול אני מניח שהוא הקונטור הכי גדול. פה רציתי להציג את הקונטורים על התמונה המקורית.
להלן הקוד:
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
// A Simple Camera Capture Framework
CvSeq* find_biggest_contour(CvSeq** first_contour);
int main() {
CvCapture* capture = cvCaptureFromCAM( 0 );//choose the webcam
IplImage* frame;
IplImage* gauss;
IplImage* gray;
IplImage* trash;
CvMemStorage* storage;
CvSeq** first_contour;
CvSeq* selected;
int Num_Of_Obj;
if ( !capture ) {
fprintf( stderr, "ERROR: capture is NULL \n" );
getchar();
return -1;
}
cvNamedWindow( "mywindow", CV_WINDOW_AUTOSIZE );//create window
while ( 1 ) {
frame = cvQueryFrame( capture );//capture single frame from camera
if ( !frame ) {
fprintf( stderr, "ERROR: frame is null.\n" );
getchar();
break;
}
//actual image processing starts here
gray = cvCreateImage( cvGetSize(frame), IPL_DEPTH_8U, 1 );
cvCvtColor( frame, gray, CV_BGR2GRAY );//converting to grayscale
gauss = cvCreateImage(cvGetSize(gray),IPL_DEPTH_8U,1);
cvSmooth( gray, gauss, CV_GAUSSIAN, 3, 3 );//Gaussian filter
trash=cvCreateImage(cvGetSize(gauss),IPL_DEPTH_8U, 1);
cvThreshold(gauss,trash,60,255,CV_THRESH_BINARY_IN V);
Num_Of_Obj=cvFindContours(trash, storage, first_contour);
selected=find_biggest_contour(first_contour);
cvDrawContours(frame, selected,10.0,0.0,0);
cvShowImage( "mywindow", trash );//show res
if ( (cvWaitKey(10) & 255) == 27 ) break;//exit loop is esc key is pressed
}
// Releases
cvReleaseCapture( &capture );
cvDestroyWindow( "mywindow" );
cvReleaseImage(&frame);
cvReleaseImage(&gauss);
cvReleaseImage(&gray);
cvReleaseImage(&trash);
return 0;
}
CvSeq* find_biggest_contour(CvSeq** first_contour)
{
int i=0,area=0;
CvRect hand_rect;
CvSeq* cont=NULL;
CvSeq* selected=NULL;
for(cont=*first_contour; cont!=NULL; cont=cont->h_next,i++ )
{
hand_rect = cvBoundingRect(cont, 1); //Calculates the up-right bounding rectangle of a point set.
if ( (hand_rect.width*hand_rect.height) > area )
{
selected = cont; //number of the biggest contour
area = hand_rect.width*hand_rect.height; //calculate the area of the biggest contour
}
}
return(selected);
}
הקוד הזה לא התקמפל אפילו הייתה בעיה עם שורה
cvDrawContours(frame, selected,10.0,0.0,0);
למישהו יש מושג למה או אולי למה זה לא עובד?
סליחה על החפירה...