机器视觉处理的测试程序
分类:人生感悟 热度:

在机器视觉处理中,我们经常要对检测到的物体的方位特征进行评估。比如说,我们要 OCR 识别一个字符串。那么这个字符串与x轴的夹角就很重要,我们需要这个信息把这个字符串转正,然后才方便识别。

条形码识别也类似,尤其是当我们条形码不是很清晰时,首先将条形码转正,然后用各向异性的滤波器处理一下,可以让条形码变得更清晰易于读取。

这里给出一种基于统计参数的特征提取方法。这个方法已经有几十年历史了,算是个老方法,但是效果很不错,所以值得写篇文章来介绍介绍。

区域的矩

一片区域 R 的矩定义为:

当p 和q 都取 0 时,得到的就是这片区域的面积。也就是:

矩还可以归一化,也就是用上面的定义再除以面积 a。

表示的是这片区域的重心。可以用它来描述区域的位置。

归一化的矩回随区域在图像中的位置不同而变化,要去除这个影响,可以用中心矩,中心矩只反映区域本身的特征。

具体的方法是将这个区域当作一个椭圆区域,那么用上面5个参量就可以计算出椭圆的长短轴和旋转角度。具体公式如下:

机器视觉处理的测试程序

椭圆的这几个参数的图形解释如下图:

机器视觉处理的测试程序

利用这几个参数就可以确定区域的方位和尺寸了。
比如我们有下面的一幅测试图像。

机器视觉处理的测试程序

用上面方法计算出的椭圆如下:

机器视觉处理的测试程序

可以看出结果非常的好。尤其是旋转角度,计算的非常准确。

下面是我的测试代码,供参考。用到了些 Qt 的功能。
#include
#include
#include
#include
#include picturebox.h
#include

QImage threshold(const QImage image, quint8 th)
{
int height = image.height();
int width = image.width();
QImage ret(width, height, QImage::Format_Indexed8);
ret.setColorCount(256);
for(int i = 0; i 256; i++)
{
ret.setColor(i, qRgb(i, i, i));
}

for(int i = 0; i height; i ++)
{
const uchar *pSrc = (uchar *)image.constScanLine(i);
uchar *pDest = (uchar *)ret.scanLine(i);
for( int j = 0; j width; j ++)
{
pDest[j] = (pSrc[j] th)? 255: 0;
}
}
return ret;
}

QImage toGray( const QImage image )
{
int height = image.height();
int width = image.width();
QImage ret(width, height, QImage::Format_Indexed8);
ret.setColorCount(256);
for(int i = 0; i 256; i++)
{
ret.setColor(i, qRgb(i, i, i));
}

qDebug () image.format();
switch(image.format())
{
case QImage::Format_Indexed8:
case QImage::Format_Grayscale8:
for(int i = 0; i height; i ++)
{
const uchar *pSrc = (uchar *)image.constScanLine(i);
uchar *pDest = (uchar *)ret.scanLine(i);
memcpy(pDest, pSrc, width);
}
break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_PremulTIplied:
for(int i = 0; i height; i ++)
{
const QRgb *pSrc = (QRgb *)image.constScanLine(i);
uchar *pDest = (uchar *)ret.scanLine(i);

for( int j = 0; j width; j ++)
{
pDest[j] = qGray(pSrc[j]);
}
}
break;
}
return ret;
}

QPointF center(const QImage image, int value)
{
if(image.isNull() || image.format() != QImage::Format_Indexed8)
{
return QPointF(-1, -1);
}
int width = image.width();
int height = image.height();
int x_mean = 0;
int y_mean = 0;
int count = 0;
for(int j = 0; j height; j ++)
{
const uchar * p = image.constScanLine(j);
for(int i = 0; i width; i++)
{
if( p[i] == value )
{
x_mean += i;
y_mean += j;
count++;
}
}
}
return QPointF((double)x_mean / count, (double)y_mean / count);

}
struct ELLIPSE_PARA
{
double x_mean; //椭圆的中心坐标 x
double y_mean; //椭圆的中心坐标 y
double r1; //椭圆的长轴半径
double r2; //椭圆的短轴半径
double theta; //椭圆的长轴与 x 轴的夹角(逆时针)
};

/**
* @brief ellipseFit 将一片区域当作椭圆来估计五个几何参数
* @param image
* @param value
* @param para
*/
bool ellipseFit(const QImage image, int value, ELLIPSE_PARA * para)
{
if(image.isNull() || image.format() != QImage::Format_Indexed8)
{
return false;
}
QPointF c = center(image, value);

int width = image.width();
int height = image.height();
double n01 = c.x();
double n10 = c.y();

double mu20 = 0.0;
double mu02 = 0.0;
double mu11 = 0.0;

int count = 0;
for(int row = 0; row height; row ++)
{
const uchar * p = image.constScanLine(row);
for(int col = 0; col width; col++)
{
if( p[col] == value )
{
mu02 += (col - n01) * (col - n01);
mu20 += (row - n10) * (row - n10);
mu11 += (col - n01) * (row - n10);
count ++;
}
}
}
if(count == 0)
{
return false;
}
mu20 /= count;
mu02 /= count;
mu11 /= count;

double t1 = mu20 + mu02;
double t2 = mu20 - mu02;
double t3 = sqrt(t2 * t2 + 4 * mu11 * mu11);
double r1 = sqrt(2 * ( t1 + t3) );
double r2 = sqrt(2 * ( t1 - t3) );

double theta = - atan2(2 * mu11, mu02 - mu20) / 2.0;

para-r1 = r1;
para-r2 = r2;
para-theta = theta;
para-x_mean = n01;
para-y_mean = n10;

return true;
}

int main(int argc, char *argv[])
{
QApplicaTIon a(argc, argv);
QImage image(D:/test55.png);
QImage imageGray = toGray(image);
//imageGray = threshold(imageGray, 128);
ELLIPSE_PARA para;
ellipseFit(imageGray, 0, );

qDebug() para.r1;
qDebug() para.r2;
qDebug() para.theta * 180 / 3.14159;
QPointF c(para.x_mean, para.y_mean);
qDebug() c;
QPainter painter(image);
painter.setPen(Qt::red);
painter.translate(c);
painter.rotate(-para.theta * 180 / 3.14159);
painter.drawEllipse(QPointF(0, 0), para.r1, para.r2 );

PictureBox box;
box.seTImage(image);
box.show();
return a.exec();
}

上一篇:智能家居炙手可热 朝阳产业前景无限 下一篇:没有了
猜你喜欢
热门排行
精彩图文