版权声明:本文为博主原创文章,欢迎转载,转载请贴上博客地址 http://blog.csdn.net/xdg_blog https://blog.csdn.net/xdg_blog/article/details/53366907
基于OpenCV的条形码区域检测(四)
由于近期手中许多项目要做,所以这一篇一直没有更新。
在上一篇时,提到了将整幅图像进行分区块并统计每个区块中的各个像素的方向信息,以得知该区块中是否存在条形码。
///将各个区块计算Sobel,并得到每个像素的方向信息,进行统计存储
void sobelAndCalc(Mat &img) {
static int idx = 0;
///不纳入统计的梯度强度阈值比例
const float GRADIANT_THRESHOLD = 0.4f;
#ifdef FILE_SAVE
char index[10];
itoa(i, index, 10);
string indexstr(index);
#endif
///纳入统计的像素值的数量
long pixelCnt = 0;
Mat gx(img.rows, img.cols, CV_32F);
Mat gy(img.rows, img.cols, CV_32F);
Sobel(img, gx, CV_32F, 1, 0, -1);
Sobel(img, gy, CV_32F, 0, 1, -1);
///初始化角度直方图
memset(hist, 0, sizeof(long) * 8);
Mat magnitude(gx.rows, gx.cols, CV_32F);
Mat angleMat(gx.rows, gx.cols, CV_32F);
cartToPolar(gx, gy, magnitude, angleMat);
///只统计梯度强度大于最大梯度强度40%的像素点,将低于阈值的值置为0
threshold(magnitude, magnitude, gradient_maxVal*GRADIANT_THRESHOLD, gradient_maxVal, THRESH_TOZERO);
#ifdef FILE_SAVE
string filename0 = "..//results//cvtest//Magnitude - " + indexstr + ".bmp";
imwrite(filename0, magnitude);
#endif
vector<float > angleSet;
///遍历当前区块所有像素点
for (size_t y = 0; y < gx.rows; ++y) {
float* pa = angleMat.ptr<float>(y);
float* pm = magnitude.ptr<float>(y);
for (size_t x = 0; x < gx.cols*gx.channels(); ++x) {
float angle = pa[x];
///将弧度限制在0~PI的范围内
angle = angle > CV_PI ? angle - CV_PI : angle;
///当前像素点的梯度强度
float curGradient = pm[x];
///如果之前未被置为0
if (curGradient > 0) {
++pixelCnt;
///将弧度值转换为角度
float angle_new = 180.0 * angle / CV_PI;
angleSet.push_back(angle_new);
if (angle >= 0 && angle < 0.125*CV_PI) {
hist[0]++;
}
else if (angle >= 0.125*CV_PI && angle < 0.25*CV_PI) {
hist[1]++;
}
else if (angle >= 0.25*CV_PI && angle < 0.375*CV_PI) {
hist[2]++;
}
else if (angle >= 0.375*CV_PI && angle < 0.5*CV_PI) {
hist[3]++;
}
else if (angle >= 0.5*CV_PI && angle < 0.625*CV_PI) {
hist[4]++;
}
else if (angle >= 0.625*CV_PI && angle < 0.75*CV_PI) {
hist[5]++;
}
else if (angle >= 0.75*CV_PI && angle < 0.875*CV_PI) {
hist[6]++;
}
else if (angle >= 0.875*CV_PI && angle < CV_PI) {
hist[7]++;
}
}
}
}
#ifdef FILE_SAVE
string filename1 = "..//results//cvtest//Histgram - " + indexstr + ".bmp";
imwrite(filename1, drawHistgram());
#endif
///存储此区块信息
g_blockSet[idx].count = pixelCnt;
g_blockSet[idx].angleSet = angleSet;
for (int j = 0; j < 8; ++j) {
g_blockSet[idx].angleHist[j] = hist[j];
}
idx++;
}
以上代码仅供参考,涉及到的结构与全局变量请见最后一篇完整实现代码
以上就是将分割好的区块内的梯度强度信息以及角度信息的统计与存储。并生成按照将PI进行8等分统计的角度直方图(请参见代码)
并附上绘制直方图的代码(由于实现比较简单、粗糙,就未附加注释):
///绘制直方图
Mat drawHistgram() {
Mat histgram(300, 400, CV_8U);
histgram = Mat::zeros(histgram.size(), CV_8U);
long maxVal = 0;
for (int i = 0; i < 8; i++)
{
if (hist[i] > maxVal)
maxVal = hist[i];
}
if (maxVal != 0)
for (int i = 0; i < 8; i++)
{
long val = hist[i];
long intensity = cvRound((val * 300 / maxVal)*0.9);
rectangle(histgram, Point(i * 50 + 5, 300 - intensity),
Point((i * 50) + 50 - 5, 300),
CV_RGB(255, 255, 255), 3);
}
return histgram;
}