思路:
因为图像近于水平,所以采用sobel或者canny效果好一些; 车辙--sobel--滤波(不高斯)--
载入灰度图,先滤波,然后x,y方向梯度计算,分别水平/垂直阈值分割二值化,然后加权和
附上代码:
#include#include #include #include using namespace cv; using namespace std; int main() { //载入原始图 Mat image_gray_row = imread("kuang1.jpg", CV_LOAD_IMAGE_GRAYSCALE); //工程目录下应该有一张名为1.jpg的素材图 Mat img_gray = image_gray_row.clone(); resize(image_gray_row, img_gray, Size(image_gray_row.cols / 6, image_gray_row.rows / 6),0,0,INTER_LINEAR); imshow("【原图】", img_gray); blur(img_gray, img_gray, Size(3, 3)); imshow("滤波", img_gray); imwrite("滤波.jpg",img_gray); Mat img_sobelX; Mat abs_img_sobelX; Sobel(img_gray, img_sobelX,CV_16S,1,0,3,1,1, BORDER_DEFAULT); convertScaleAbs(img_sobelX, abs_img_sobelX); imshow("【效果图】 X方向Sobel", abs_img_sobelX); imwrite("【效果图】 X方向Sobel.jpg",abs_img_sobelX); Mat img_sobelY; Mat abs_img_sobelY; Sobel(img_gray, img_sobelY, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); convertScaleAbs(img_sobelY, abs_img_sobelY); imshow("【效果图】 Y方向Sobel", abs_img_sobelY); imwrite("【效果图】 Y方向Sobel.jpg", abs_img_sobelY); Mat dst; addWeighted(abs_img_sobelX, 0.5, abs_img_sobelY, 0.5, 0, dst); imshow("【效果图】整体方向Sobel", dst); imwrite("【效果图】整体方向Sobel.jpg",dst); Mat dst_up; Mat dst_upX; Mat dst_upY; dst_up.create(dst.size(), dst.type()); dst_upX.create(dst.size(), dst.type()); dst_upY.create(dst.size(), dst.type()); // threshold(abs_img_sobelY, dst_upY, 96, 255, THRESH_OTSU + THRESH_BINARY); // imshow("检测垂直阈值分割", dst_upY); // threshold(img_sobelX, dst_upX, 96, 255, THRESH_OTSU + THRESH_BINARY); // imshow("检测水平阈值分割", dst_upX); threshold(dst, dst_up, 84, 255, THRESH_BINARY); imshow("整体二值化",dst_up); imwrite("整体二值化.jpg", dst_up); waitKey(0); return 0; }
提示:注意全局变量!!!! Mat 和 参数都得是全局变量!main里面不要重申!
附上带trackbar的代码:
#include#include #include #include #include #include using namespace cv; using namespace std; int threshold_value = 30; Mat image_gray_row, img_gray, img_sobelX, abs_img_sobelX, img_sobelY, abs_img_sobelY, dst, dst_up, dst_upX, dst_upY; /// 自定义函数声明 static void Threshold_Demo(int, void*); int main() { //载入原始图 image_gray_row = imread("kuang1.jpg", CV_LOAD_IMAGE_GRAYSCALE); img_gray = image_gray_row.clone(); resize(image_gray_row, img_gray, Size(image_gray_row.cols / 6, image_gray_row.rows / 6), 0, 0, INTER_LINEAR); blur(img_gray, img_gray, Size(3, 3)); Sobel(img_gray, img_sobelX, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT); convertScaleAbs(img_sobelX, abs_img_sobelX); Sobel(img_gray, img_sobelY, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT); convertScaleAbs(img_sobelY, abs_img_sobelY); addWeighted(abs_img_sobelX, 0.5, abs_img_sobelY, 0.5, 0, dst); dst_up.create(dst.size(), dst.type()); dst_upX.create(dst.size(), dst.type()); dst_upY.create(dst.size(), dst.type()); // threshold(abs_img_sobelY, dst_upY, 96, 255, THRESH_OTSU + THRESH_BINARY); // imshow("检测垂直阈值分割", dst_upY); // threshold(img_sobelX, dst_upX, 96, 255, THRESH_OTSU + THRESH_BINARY); // imshow("检测水平阈值分割", dst_upX); namedWindow("Demo", CV_WINDOW_AUTOSIZE); //创建滑动条来控制阈值 createTrackbar("Threshold", "Demo", &threshold_value, 255, Threshold_Demo); Threshold_Demo(0, 0);//结果在回调函数中显示 waitKey(0); return 0; } void Threshold_Demo(int, void*) { threshold(dst, dst_up, threshold_value, 255, THRESH_BINARY); imshow("Demo", dst_up); }
待改进:
霍夫变换–找线
路–k只有一个,路正交—-拉普拉斯强化边缘,二值化
管道(拉普拉斯锐化/膨胀和腐蚀,二值化,分离,零交叉)
–以下为闭环区域
颜色特征识别(煤堆)—闭环后中间杂质()可忽略,已闭环
RGB,UIV,LAD,色态聚类(不固定集群,需要贪婪,簇的合并问题-中心点相近放一块-!-!-同一簇的分离(根据像素的距离再聚类),sobel算子迭代,识别出边缘轮廓后拼接填洞
膨胀和腐蚀
检测纹理复杂程度–判断煤堆
路灯(路灯两侧相对比较高–波峰波谷)