Smorodov 579 Жалоба Опубликовано July 12, 2012 Написал протенький код для экспериментов с вариациями на тему Хафа: #include <iostream> #include <vector> #include <stdio.h> #include "opencv2/core/core.hpp" #include "opencv2/core/gpumat.hpp" #include "opencv2/core/opengl_interop.hpp" #include "opencv2/gpu/gpu.hpp" #include "opencv2/ml/ml.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/contrib/contrib.hpp" #include "opencv2/video/tracking.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "fstream" #include "iostream" using namespace std; using namespace cv; //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- Mat HoughTransform(Mat &src,vector<Point> pts) { // максимальное расстояние от начала координат до точки изобажения int Rmax=sqrtl(powl(src.rows,2)+powl(src.cols,2)); // ищем с разрешением в 1 градус int thetaMax=360; Mat acc=Mat::zeros(Rmax,thetaMax,CV_32FC1); for(int i=0;i<pts.size();i++) { // x cosθ + y sinθ = R for(int theta=0;theta<thetaMax;theta++) { double thetaRadians=static_cast<float>(theta)*CV_PI/180.0; double Rd=pts[i].x*cos(thetaRadians)+pts[i].y*sin(thetaRadians); if(Rd>0 && Rd<Rmax) { acc.at<float>((int)Rd,theta)+=1; } } } cv::GaussianBlur(acc,acc,Size(3,3),1); return acc; } //---------------------------------------------------------------------- // поиск локальных максимумов //---------------------------------------------------------------------- void FindLines(Mat& img,vector<Point>& pts) { vector<Rect> Rects; Mat img8U( img.size(), CV_8UC3 ); cv::normalize(img,img,0,255,CV_MINMAX); img.convertTo(img8U,CV_8UC1); Mat rect_12 = getStructuringElement(CV_SHAPE_RECT, Size(3,3)); erode(img8U, img8U, rect_12,Point(),1); Mat rect_6 = getStructuringElement(CV_SHAPE_RECT, Size(3,3)); dilate(img8U,img8U,rect_6,Point(),2); vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours(img8U,contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point()); if(contours.size()>0) { for( int i = 0; i < contours.size(); i++ ) { //if(contourArea(contours[i])>5) //{ Rect r=cv::boundingRect(contours[i]); Rects.push_back(r); //} } } if(Rects.size()>1) { for(int i=0;i<Rects.size();i++) { Mat subImg=img(Rects[i]); double M,m; Point p,P; minMaxLoc(subImg,&m,&M,&p,&P); P.x+=Rects[i].x; P.y+=Rects[i].y; pts.push_back(P); } } Rects.clear(); } //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- void drawLines(Mat& img,vector<Point>& par) { for(int i=0;i<par.size();i++) { double R=par[i].y; double th=par[i].x/180.0*CV_PI; if(fabs(sin(th))>fabs(cos(th))) { for(int m=0;m<img.cols;m++) { int x=m; int y=(R-(double)x*cosl(th))/sinl(th); if(x>0 && x<img.cols && y>0 && y<img.rows) { img.at<unsigned char>(y,x)=128; } } } else { for(int m=0;m<img.rows;m++) { int y=m; double R=par[i].y; double th=par[i].x/180.0*CV_PI; int x=(R-(double)y*sin(th))/cos(th); if(x>0 && x<img.cols && y>0 && y<img.rows) { img.at<unsigned char>(y,x)=128; } } } } } //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- int main( int argc, char** argv ) { int width; int height; Mat Img=imread("C:\\ImagesForTest\\lines.jpg",0); width=Img.cols; height=Img.rows; // Сначала выделим границы Mat Edges; cv::Canny(Img,Edges,200,200,3,true); namedWindow("Edges"); imshow("Edges",Edges); // Чтобы не перелопачивать все изображение запомним точки границ vector<Point> pts; for(int i=0;i<Edges.rows;i++) { for(int j=0;j<Edges.cols;j++) { if(Edges.at<unsigned char>(i,j)>0){pts.push_back(Point(j,i));} } } // Преобразование Хафа переведем точки в параметрическое пространство прямых Mat HoughAccumulator; HoughAccumulator=HoughTransform(Edges,pts); cv::normalize(HoughAccumulator,HoughAccumulator,0,1,CV_MINMAX); namedWindow("HoughAccumulator"); imshow("HoughAccumulator",HoughAccumulator); Mat mean,stdDev; cv::meanStdDev(HoughAccumulator,mean,stdDev); double Mean=mean.at<double>(0,0); HoughAccumulator-=Mean; // Выровняем относительно нуля // сигма применяется к целочисленному изображению, поэтоу домножим double StdDev=stdDev.at<double>(0,0)*255; // Порог по аккумулятору (разбиваем картинку на участки, в которых будем искать локальные максимумы) Mat thrAcc; HoughAccumulator.convertTo(thrAcc,CV_8UC1,255); // зададим порог отсечения (меньше порог - больше прямых) // Погрог 3 сигмы (отсекаем почти все) cv::threshold(thrAcc,thrAcc,3*StdDev,255,3); // Найдем параметры прямых, за которые саккумулировалось наибольшее кол-во голосов vector<Point> LinesParams; /* GridAdaptedFeatureDetector detect(new FastFeatureDetector(10), 100, 10, 10); vector<KeyPoint> keypoints; // Ключевые точки (CPU) detect.detect(thrAcc,keypoints); for (int i=0;i<keypoints.size();i++) { LinesParams.push_back(keypoints[i].pt); } */ FindLines(thrAcc,LinesParams); cout << LinesParams.size() << endl; // Нарисуем точки в пространстве параметров (каждая точка - это прямая) for(int i=0;i<LinesParams.size();i++) { circle(thrAcc,Point(LinesParams[i]),3,CV_RGB(255,255,255),-1); } namedWindow("thrAcc"); imshow("thrAcc",thrAcc); // Нарисуем прямые по заданным параметрам drawLines(Img,LinesParams); namedWindow("Image"); imshow("Image",Img); waitKey(0); pts.clear(); return 0; } [/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 12, 2012 Вариант детектора отрезков: #include <iostream> #include <vector> #include <stdio.h> #include "opencv2/core/core.hpp" #include "opencv2/core/gpumat.hpp" #include "opencv2/core/opengl_interop.hpp" #include "opencv2/gpu/gpu.hpp" #include "opencv2/ml/ml.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/contrib/contrib.hpp" #include "opencv2/video/tracking.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "fstream" #include "iostream" using namespace std; using namespace cv; //----------------------------------------------------------------------------------------------------- // Переводим точки границ в пространство параметров прямой линии (в полярных координатах) //----------------------------------------------------------------------------------------------------- Mat HoughTransform(Mat &src,vector<Point> pts) { // максимальное расстояние от начала координат до точки изобажения int Rmax=sqrtl(powl(src.rows,2)+powl(src.cols,2)); // ищем с разрешением в 1 градус int thetaMax=360; Mat acc=Mat::zeros(Rmax,thetaMax,CV_32FC1); for(int i=0;i<pts.size();i++) { // x cosθ + y sinθ = R for(int theta=0;theta<thetaMax;theta++) { double thetaRadians=static_cast<float>(theta)*CV_PI/180.0; double Rd=pts[i].x*cos(thetaRadians)+pts[i].y*sin(thetaRadians); if(Rd>0 && Rd<Rmax) { acc.at<float>((int)Rd,theta)+=1; } } } cv::GaussianBlur(acc,acc,Size(3,3),1); return acc; } //---------------------------------------------------------------------- // поиск локальных максимумов //---------------------------------------------------------------------- void FindLines(Mat& img,vector<Point>& pts) { vector<Rect> Rects; Mat img8U( img.size(), CV_8UC3 ); cv::normalize(img,img,0,255,CV_MINMAX); img.convertTo(img8U,CV_8UC1); Mat rect_12 = getStructuringElement(CV_SHAPE_RECT, Size(3,3)); erode(img8U, img8U, rect_12,Point(),1); Mat rect_6 = getStructuringElement(CV_SHAPE_RECT, Size(3,3)); dilate(img8U,img8U,rect_6,Point(),2); vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours(img8U,contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point()); if(contours.size()>0) { for( int i = 0; i < contours.size(); i++ ) { //if(contourArea(contours[i])>5) //{ Rect r=cv::boundingRect(contours[i]); Rects.push_back(r); //} } } if(Rects.size()>1) { for(int i=0;i<Rects.size();i++) { Mat subImg=img(Rects[i]); double M,m; Point p,P; minMaxLoc(subImg,&m,&M,&p,&P); P.x+=Rects[i].x; P.y+=Rects[i].y; pts.push_back(P); } } Rects.clear(); } //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- void drawLines(Mat& img,vector<Point>& par,vector<Point>& pts,int gap) { for(int i=0;i<par.size();i++) { double R=par[i].y; double th=par[i].x/180.0*CV_PI; if(fabs(sin(th))>fabs(cos(th))) // Чтобы не делить на ноль и малые числа (для вертикальных и горизонтальных линий) { for(int m=0;m<pts.size();m++) { int x=pts[m].x; int y=(R-(double)x*cosl(th))/sinl(th); if(fabsl(y-pts[m].y)<gap && x>0 && x<img.cols && y>0 && y<img.rows) // Если точка не слишком далеко от прямой, нарисуем её { img.at<unsigned char>(y,x)=128; // Отмечаем точку } } } else { for(int m=0;m<pts.size();m++) { int y=pts[m].y; int x=(R-(double)y*sin(th))/cos(th); if(fabsl(x-pts[m].x)<gap && x>0 && x<img.cols && y>0 && y<img.rows) // Если точка не слишком далеко от прямой, нарисуем её { img.at<unsigned char>(y,x)=128; // Отмечаем точку } } } } } //----------------------------------------------------------------------------------------------------- // //----------------------------------------------------------------------------------------------------- int main( int argc, char** argv ) { int width; int height; Mat Img=imread("C:\\ImagesForTest\\lines.jpg",0); width=Img.cols; height=Img.rows; // Сначала выделим границы Mat Edges; cv::Canny(Img,Edges,200,200,3,true); namedWindow("Edges"); imshow("Edges",Edges); // Чтобы не перелопачивать все изображение запомним точки границ vector<Point> pts; for(int i=0;i<Edges.rows;i++) { for(int j=0;j<Edges.cols;j++) { if(Edges.at<unsigned char>(i,j)>0){pts.push_back(Point(j,i));} } } // Преобразование Хафа переведем точки в параметрическое пространство прямых Mat HoughAccumulator; HoughAccumulator=HoughTransform(Edges,pts); cv::normalize(HoughAccumulator,HoughAccumulator,0,1,CV_MINMAX); namedWindow("HoughAccumulator"); imshow("HoughAccumulator",HoughAccumulator); Mat mean,stdDev; cv::meanStdDev(HoughAccumulator,mean,stdDev); double Mean=mean.at<double>(0,0); HoughAccumulator-=Mean; // Выровняем относительно нуля // сигма применяется к целочисленному изображению, поэтоу домножим double StdDev=stdDev.at<double>(0,0)*255; // Порог по аккумулятору (разбиваем картинку на участки, в которых будем искать локальные максимумы) Mat thrAcc; HoughAccumulator.convertTo(thrAcc,CV_8UC1,255); // зададим порог отсечения (меньше порог - больше прямых) // Погрог 3 сигмы (отсекаем почти все) cv::threshold(thrAcc,thrAcc,3*StdDev,255,3); // Найдем параметры прямых, за которые саккумулировалось наибольшее кол-во голосов vector<Point> LinesParams; FindLines(thrAcc,LinesParams); cout << LinesParams.size() << endl; // Нарисуем точки в пространстве параметров (каждая точка - это прямая) for(int i=0;i<LinesParams.size();i++) { circle(thrAcc,Point(LinesParams[i]),3,CV_RGB(255,255,255),-1); } namedWindow("thrAcc"); imshow("thrAcc",thrAcc); // Нарисуем прямые по заданным параметрам // Здесь точки границ, подставляются в уравнения прямых (чтобы получались отрезки, а не бесконечные прямые) drawLines(Img,LinesParams,pts,20); namedWindow("Image"); imshow("Image",Img); waitKey(0); pts.clear(); return 0; }[/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано December 12, 2013 Наглядная демонстрация преобразования Хафа: Здесь скрипт: http://www.activovision.com/octavi/doku.php?id=hough_transform Видео работы скрипта: Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах