参考了一篇论文的思想,主要思路就是通过分块求取各窗口内的梯度方向,利用密度阈值过滤。缺点是要手动定义窗口大小和密度值。
具体代码如下:
//窗口内计算边缘密度特征
struct EdgeDensity
{int num; //边缘点数float orient; //边缘梯度方向
};
//排序
bool pairSortFun3(EdgeDensity elem1, EdgeDensity elem2)
{return elem1.num > elem2.num; //降序
}
//求取主梯度方向
float GetCodeRegionOrient(Mat MatGray, int w, int h, int thre_gradient_density)
{//滤波blur(MatGray, MatGray, Size(3, 3));//求梯度cv::Mat magX = cv::Mat(MatGray.rows, MatGray.cols, CV_32F);cv::Mat magY = cv::Mat(MatGray.rows, MatGray.cols, CV_32F);cv::Sobel(MatGray, magX, CV_32F, 1, 0, 3);cv::Sobel(MatGray, magY, CV_32F, 0, 1, 3);Mat magnitude = Mat(MatGray.size(), CV_32FC1); // 梯度幅值Mat slopes = Mat(MatGray.size(), CV_32FC1); // 梯度方向int i, j;float v1, v2, v, direc;for (i = 0; i < MatGray.rows; i++){for (j = 0; j < MatGray.cols; j++){v1 = magX.at<float>(i, j);v2 = magY.at<float>(i, j);v = sqrt(v1*v1 + v2*v2); //求出梯度magnitude.at<float>(i, j) = v;if (v1 == 0){if (v2 != 0){direc = 90;}else{direc = 255;}}else{direc = atan(v2 / v1)* (180 / CV_PI);if (direc < 0){direc += 180;}int t = direc / 2;if (direc - t * 2 < (t + 1) * 2 - direc){direc = t * 2;}else{direc = (t + 1) * 2;}}slopes.at<float>(i, j) = direc;}}
Mat magtmp;magnitude.convertTo(magnitude, CV_8U);cv::threshold(magnitude, magnitude, 30, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);magnitude.convertTo(magtmp, CV_32F);//矩形窗口Mat dstM = Mat::zeros(magnitude.size(), CV_8UC1);for (i = 1; i < magnitude.rows - 1; i++){for (j = 1; j < magnitude.cols - 1; j++){for (int m = -1; m <= 1; m++) // 3*3{for (int n = -1; n <= 1; n++){if ((magtmp.at<float>(i, j) == 255) && ((slopes.at<float>(i + m, j + n) == slopes.at<float>(i, j)) && slopes.at<float>(i, j) != 255)){if (m != 0 && n != 0){dstM.at<uchar>(i + m, j + n) = 255;dstM.at<uchar>(i, j) = 255;}}}}}}//分块计算主方向vector<EdgeDensity> dirVec;dirVec.clear();for (i = h; i < dstM.rows - h;){for (j = w; j < dstM.cols - w;){//计算块的主方向vector<float> d;d.clear();for (int m = -h; m <= h; m++){for (int n = -w; n <= w; n++){if (dstM.at<uchar>(i + m, j + n) == 255){float ori = slopes.at<float>(i + m, j + n);d.push_back(ori);}}}if (d.size() < 2){j += (2 * w + 1);continue;}std::sort(d.begin(), d.end());int index = 0, seqIndex = 0;int index_begin, seqIndex_begin = 0;for (int q = 0; q < d.size(); q++){if (q == d.size() - 1){if (d[q] == d[q - 1] && index != 0){if (index > seqIndex){seqIndex = index;seqIndex_begin = index_begin;}}break;}if (d[q + 1] == d[q]){if (index == 0){index_begin = q;}index++;}else{if (index > seqIndex){seqIndex = index;seqIndex_begin = index_begin;}index = 0;}}int len = d.size();if (seqIndex_begin < len){EdgeDensity ey;ey.num = seqIndex + 1;ey.orient = d[seqIndex_begin];dirVec.push_back(ey);}j += (2 * w + 1);}i += (2 * h + 1);}//找出主方向vector<float> orientVec;orientVec.clear();std::sort(dirVec.begin(), dirVec.end(), pairSortFun3);for (int c = 0; c < dirVec.size(); c++){if (dirVec[c].num > thre_gradient_density) // 剔除密度低的块{orientVec.push_back(dirVec[c].orient);}}if (orientVec.size() < 1){return -1;}std::sort(orientVec.begin(), orientVec.end());//标记seqIndex_begin 为主方向的索引int cnt = 0, seqCnt = 0;int index_begin, seqIndex_begin = 0;if (orientVec.size() == 1){seqIndex_begin = 0;seqCnt = 1;}else{for (int q = 0; q < orientVec.size(); q++){if (q == orientVec.size() - 1){if (orientVec[q] == orientVec[q - 1] && cnt != 0){if (cnt > seqCnt){seqCnt = cnt;seqIndex_begin = index_begin;}}break;}if (orientVec[q + 1] == orientVec[q]){if (cnt == 0){index_begin = q;}cnt++;}else{if (cnt > seqCnt){seqCnt = cnt;seqIndex_begin = index_begin;}cnt = 0;}}}return orientVec[seqIndex_begin];
}
效果图如下: