--- tags: C++, OpenCV disqus: HackMD --- 電腦視覺 Homework #1 === A. 附圖Image_a.jpg 為一張具有車道隔線之道路圖,請利用Hough Transform方法將白色車道隔線取出。參考步驟如下:1. 將圖轉為灰階圖,然後利用適當之Edge detector取得Edge map;2. 利用Line Hough Transform轉換產生參數空間之統計陣列 (Accumulator array),並將此陣列以圖形呈現;3. 由參數空間之統計陣列找出屬於車道隔線之Lines;4. 將上步驟之結果套至原圖中,以輸出白色車道隔線。(30%) --- 原圖: ![](https://i.imgur.com/iUU8b7G.jpg) Accumulator array圖與隔線位置圖: ![](https://i.imgur.com/qtD6bHy.png) ![](https://i.imgur.com/qsvKYki.png) 對照原圖之檢出的線: ![](https://i.imgur.com/4RZeq6W.jpg) ![](https://i.imgur.com/CFxP4hC.png) --- A1. 5. 若透過車子上之攝影設備取得連續之畫面,說明如何將它應用到車子輔助駕駛 中之是否偏離車道的判斷?(15%) --- 將影片取出一張一張的照片,找出白色隔線,並判斷車頭左右邊各取一個定位點,通過定位點與白色隔線距離判斷是否偏離車道。 --- B. 附圖Image_b.jpg 為一張同時具有多枚台幣1元,5元,10元 與50元之圖,請利用Hough Transform 方法來算算看各個幣別之個數。參考步驟如下:1. 將圖轉為灰階圖,然後利用適當之Edge detector取得Edge map;2. 利用Circle Hough Transform 轉換產生參數空間之統計陣列(Accumulator array),並將此陣列以圖形呈現;3. 由參數空間之統計陣列找出屬於各個幣別之Circles;4. 將上步驟之結果套至原圖中,只取出各個幣別之圖輸出。(40%) --- 原圖: ![](https://i.imgur.com/E8fG3vU.jpg) Accumulator array圖與隔線位置圖: ![](https://i.imgur.com/tX9x9gZ.png) ![](https://i.imgur.com/5auPctR.png) 對照原圖之檢出的圓: ![](https://i.imgur.com/ulGzllu.jpg) ![](https://i.imgur.com/SiztC3a.png) 紅色:一元 黃色:五元 紫色:十元 藍色:五十元 判斷幣別方式: 先找到圓的位置,再判斷各圓之半徑 ```cpp= int radius = c[2]; if (radius < 65) { return "NT$1"; } else if (radius >= 65 && radius < 75) { return "NT$5"; } else if (radius >= 75 && radius < 85) { return "NT$10"; } else if (radius >= 85) { return "NT$50"; } ``` ``` X:732 Y:214 radius:87 NT$50 X:696 Y:692 radius:80 NT$10 X:406 Y:726 radius:86 NT$50 X:870 Y:420 radius:80 NT$10 X:280 Y:384 radius:80 NT$10 X:636 Y:450 radius:82 NT$10 X:306 Y:174 radius:66 NT$5 X:430 Y:340 radius:62 NT$1 X:948 Y:608 radius:63 NT$1 X:402 Y:528 radius:61 NT$1 X:1032 Y:246 radius:70 NT$5 ``` --- C. 將B.中利用Hough Transform Circles公式檢測的做法改為透過建立 R-table方法實現之。(15%) 截取硬幣圖,使用template matching的方式找出圓 ![](https://i.imgur.com/cfqHQtS.png) ![](https://i.imgur.com/OYxpSty.jpg) ![](https://i.imgur.com/luO4dWF.png) --- 程式原始碼 --- ```cpp= #include <iostream> #include <thread> #include <chrono> #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include "opencv2/ximgproc.hpp" using namespace std; using namespace cv; using namespace cv::ximgproc; Mat dstLines; Mat dstCircles; Mat dstHoughTransformLines; Mat dstHoughTransformCircles; Mat dstHoughTransformLinesSpace; Mat dstHoughTransformCirclesSpace; const char* image_window = "Source Image"; const char* result_window = "Result window"; int match(string filename, string templatename); void display_template_matching(); void MatchingMethod( int, void* ); class HoughTrans { private: thread* t; string window_name; Mat src; Mat dstHoughTransform; Mat srctemplate; int DELAY_CAPTION = 1500; void display_caption(Mat dst, const char* caption) { Mat src = Mat::zeros(dst.size(), dst.type()); putText(src, caption, Point(src.cols/4, src.rows/2), FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255)); display_dst(src, DELAY_CAPTION); } void display_dst(Mat dst, int delay) { imshow(window_name, dst); waitKey(delay); } void display_hough_lines() { // 圖片深複製,放在新的記憶體空間 Mat dst = src.clone(); Mat orignImg = src.clone(); // 將圖片轉灰階圖 cvtColor(dst, dst, COLOR_BGR2GRAY); // GaussianBlur Image GaussianBlur(dst, dst, Size(3, 3), 0, 0); // Edge Image int low_threshold = 50; int high_threshold = 150; Canny(dst, dst, low_threshold, high_threshold); // Masked Image, 將車道視線範圍外的線條遮蓋 Mat MaskImg = Mat::zeros(dst.size(), CV_8UC1); int ignore_mask_color = 255; Point rook_points[1][4]; rook_points[0][0] = Point(0, dst.rows); rook_points[0][1] = Point(400, 350); rook_points[0][2] = Point(550, 350); rook_points[0][3] = Point(dst.cols, dst.rows); const Point* ppt[1] = { rook_points[0] }; int npt[] = { 4 }; fillPoly(MaskImg, ppt, npt, 1, Scalar(ignore_mask_color), LINE_8, 0); bitwise_and(dst, MaskImg, dst); // Draw lines vector<Vec4f> lines; HoughLinesP(dst, lines, 1, M_PI/180, 20, 5, 150); dstHoughTransform = Mat::zeros(src.size(), src.type()); for (size_t i = 0; i < lines.size(); i++) { Vec4i l = lines[i]; line(orignImg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 12, LINE_AA); line(dstHoughTransform, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 12, LINE_AA); } dstLines = orignImg.clone(); } void display_hough_circles() { // 圖片深複製,放在新的記憶體空間 Mat dst = src.clone(); Mat orignImg = src.clone(); // 將圖片轉灰階圖 cvtColor(dst, dst, COLOR_BGR2GRAY); // MedianBlur Image medianBlur(dst, dst, 5); // Edge Image int low_threshold = 50; int high_threshold = 100; Canny(dst, dst, low_threshold, high_threshold); // Draw Circles vector<Vec3f> circles; HoughCircles(dst, circles, HOUGH_GRADIENT, 1, dst.rows/8, // change this value to detect circles with different distances to each other 100, 30, 50, 150 // change the last two parameters ); dstHoughTransform = Mat::zeros(src.size(), src.type()); for( size_t i = 0; i < circles.size(); i++ ) { Vec3i c = circles[i]; Point center = Point(c[0], c[1]); // circle center circle(src, center, 1, Scalar(0,100,100), 3, LINE_AA); // circle outline int radius = c[2]; if (radius < 65) { circle(src, center, radius, Scalar(0, 0, 255), 3, LINE_AA); circle(dstHoughTransform, center, radius, Scalar(0, 0, 255), 3, LINE_AA); cout << "X:" << c[0] << " " << "Y:" << c[1] << " " << "radius:" << c[2] << " " << "NT$1" << endl; } else if (radius >= 65 && radius < 75) { circle(src, center, radius, Scalar(0, 255, 255), 3, LINE_AA); circle(dstHoughTransform, center, radius, Scalar(0, 255, 255), 3, LINE_AA); cout << "X:" << c[0] << " " << "Y:" << c[1] << " " << "radius:" << c[2] << " " << "NT$5" << endl; } else if (radius >= 75 && radius < 85) { circle(src, center, radius, Scalar(255, 0, 255), 3, LINE_AA); circle(dstHoughTransform, center, radius, Scalar(255, 0, 255), 3, LINE_AA); cout << "X:" << c[0] << " " << "Y:" << c[1] << " " << "radius:" << c[2] << " " << "NT$10" << endl; } else if (radius >= 85) { circle(src, center, radius, Scalar(255, 255, 0), 3, LINE_AA); circle(dstHoughTransform, center, radius, Scalar(255, 255, 0), 3, LINE_AA); cout << "X:" << c[0] << " " << "Y:" << c[1] << " " << "radius:" << c[2] << " " << "NT$50" << endl; } } dstCircles = src.clone(); } void houghtransform(Mat const &fht) { double minv(0),maxv(0); minMaxLoc(fht,&minv,&maxv); Mat ucharFht; fht.convertTo(ucharFht, CV_MAKETYPE(CV_8U, fht.channels()), 255.0/(maxv+minv), minv/(maxv+minv)); dstHoughTransform = ucharFht.clone(); } public: HoughTrans(string _window_name, Mat _src) { HoughTrans::window_name = _window_name; HoughTrans::src = _src; } ~HoughTrans() { cv::destroyAllWindows(); } void Run() { if (window_name == "HoughLines") { display_hough_lines(); } else if (window_name == "HoughCircles") { display_hough_circles(); } } void ShowHoughTransform(Mat *dst, Mat *dstSpace) { *dst = dstHoughTransform.clone(); Mat hough; ximgproc::FastHoughTransform(dstHoughTransform, hough, CV_32S, 6, 2, 1); // dst is source image houghtransform(hough); *dstSpace = dstHoughTransform; } }; int main() { char window_HoughLines[] = "HoughLines"; char window_HoughCircles[] = "HoughCircles"; char window_HoughTransformLinesSpace[] = "HoughTransformLinesSpace"; char window_HoughTransformCirclesSpace[] = "HoughTransformCirclesSpace"; char window_HoughTransformLines[] = "HoughTransformLines"; char window_HoughTransformCircles[] = "HoughTransformCircles"; char window_TemplateMatching[] = "TemplateMatching"; // 載入圖片到src const char* filename = "image_a.jpg"; Mat src = imread(samples::findFile( filename ), IMREAD_COLOR); if (src.empty()) { cout << "Error opening image" << endl; return EXIT_FAILURE; } // 載入圖片到src2 const char* filename2 = "image_b.jpg"; Mat src2 = imread(samples::findFile( filename2 ), IMREAD_COLOR); if (src2.empty()) { cout << "Error opening image" << endl; return EXIT_FAILURE; } // 載入圖片到src3 const char* filename3 = "image_b_cut.jpg"; Mat src3 = imread(samples::findFile( filename3 ), IMREAD_COLOR); if (src3.empty()) { cout << "Error opening image" << endl; return EXIT_FAILURE; } std::cout << "Waiting..." << std::endl; namedWindow(window_HoughLines, WINDOW_AUTOSIZE); namedWindow(window_HoughCircles, WINDOW_AUTOSIZE); namedWindow(window_HoughTransformLinesSpace, WINDOW_AUTOSIZE); namedWindow(window_HoughTransformCirclesSpace, WINDOW_AUTOSIZE); namedWindow(window_HoughTransformLines, WINDOW_AUTOSIZE); namedWindow(window_HoughTransformCircles, WINDOW_AUTOSIZE); namedWindow(window_TemplateMatching, WINDOW_AUTOSIZE); imshow(window_HoughLines, src); imshow(window_HoughCircles, src2); imshow(window_TemplateMatching, src3); HoughTrans demo1(window_HoughLines, src); HoughTrans demo2(window_HoughCircles, src2); demo1.Run(); demo1.ShowHoughTransform(&dstHoughTransformLines, &dstHoughTransformLinesSpace); demo2.Run(); demo2.ShowHoughTransform(&dstHoughTransformCircles, &dstHoughTransformCirclesSpace); //display_template_matching(); match(filename2, filename3); std::cout << "Finished." << std::endl; imshow(window_HoughLines, dstLines); imshow(window_HoughCircles, dstCircles); imshow(window_HoughTransformLinesSpace, dstHoughTransformLinesSpace); imshow(window_HoughTransformCirclesSpace, dstHoughTransformCirclesSpace); imshow(window_HoughTransformLines, dstHoughTransformLines); imshow(window_HoughTransformCircles, dstHoughTransformCircles); waitKey(); return EXIT_SUCCESS; } int match(string filename, string templatename) { Mat ref = cv::imread(filename); Mat tpl = cv::imread(templatename); Mat dst = ref.clone(); Mat dstTpl = tpl.clone(); // 將圖片轉灰階圖 cvtColor(dst, dst, COLOR_BGR2GRAY); cvtColor(dstTpl, dstTpl, COLOR_BGR2GRAY); //medianBlur(dst, dst, 5); GaussianBlur(dst, dst, Size(3, 3), 0, 0); int low_threshold = 150; int high_threshold = 200; Canny(dst, dst, low_threshold, high_threshold); Mat sx, sy; Sobel(dst, sx, -1, 1, 0); Sobel(dst, sy, -1, 0, 1); Mat image_input = abs(sx) + abs(sy); //medianBlur(dstTpl, dstTpl, 5); GaussianBlur(dstTpl, dstTpl, Size(3, 3), 0, 0); Canny(dstTpl, dstTpl, low_threshold, high_threshold); Mat sx2, sy2; Sobel(dstTpl, sx2, -1, 1, 0); Sobel(dstTpl, sy2, -1, 0, 1); Mat template_input = abs(sx2) + abs(sy2); Mat match_result; matchTemplate(image_input, template_input, match_result, 5); Mat thresholded; threshold(match_result, thresholded, 0.2, 1, THRESH_BINARY); while (true) { double minval, maxval, threshold = 0.9; Point minloc, maxloc; minMaxLoc(thresholded, &minval, &maxval, &minloc, &maxloc); if (maxval >= threshold) { rectangle(ref, maxloc, Point(maxloc.x + tpl.cols, maxloc.y + tpl.rows), CV_RGB(0,255,0), 2); floodFill(thresholded, maxloc, 0); //mark drawn blob } else break; } imshow("final", ref); return 0; } ```