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

在机器视觉处理中,我们经常要对检测到的物体的方位特征进行评估。比如说,我们要 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();
}

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2024年4月16日 – 专注于引入新品的全球电子元器件和工业自动化产品授权代理商贸泽电子 (Mouser Electronics) 宣布其屡获殊荣的Empowering Innovation Together (共求创...

关键字: 机器视觉 电子元器件

2024年4月2日 – 专注于引入新品的全球电子元器件和工业自动化产品授权代理商贸泽电子 (Mouser Electronics) 即日起供货Texas Instruments的TDES9640 V3Link™解串器集线...

关键字: 机器视觉 机器人 图像传感器

借助广泛的 Teledyne GigE 和 USB3 面阵扫描相机支持,工程师可以使用 Spinnaker 快速开发用于视觉应用的软件解决方案。通过提供完全控制相机的选项,Spinnaker 允许用户管理图像处理管道的每...

关键字: 机器视觉 API 库 磁盘

2023年12月11日 – 专注于引入新品的全球电子元器件和工业自动化产品授权代理商贸泽电子 (Mouser Electronics) 即日起供应Texas Instruments的AM68Ax 64位Jacinto 8...

关键字: 机器视觉 SoC 处理器

加拿大滑铁卢——2023 年 11 月 30 日——Teledyne DALSA 很高兴地宣布其 AxCIS™ 系列高速高分辨率全集成线阵成像模块已投产。这款使用简便的接触式图像传感器(CIS)将传感器、镜头和灯合为一体...

关键字: 图像传感器 机器视觉 传感器

法国格勒诺布尔,2023 年 11 月 21 日 — Teledyne Technologies 子公司、全球成像解决方案革新者 Teledyne e2v 发布全新高水准 CMOS 图像传感器系列 Emerald™ Ge...

关键字: 图像传感器 机器视觉 监控相机

以“新时代,共享未来”为主题的第六届中国国际进口博览会在上海圆满落下帷幕,再次奏响了中国持续推进高水平对外开放、与世界共享中国大市场发展机遇的最强音。通过进博会这个平台,越来越多的跨国企业将创新的技术和成果快步引入中国,...

关键字: 人工智能 机器视觉 边缘计算

2023年9月14日,中国上海—— 全球领先的技术分销商和解决方案提供商安富利将于9月19日至23日在第二十三届中国国际工业博览会(以下简称“工博会”)上重磅亮相,集中展示安富利及其生态合作伙伴在人工智能、机器视觉和边缘...

关键字: 人工智能 机器视觉 边缘计算

随着人工智能和计算机视觉技术的快速发展,机器视觉在各个领域得到了广泛应用。从自动驾驶、工业自动化到医疗诊断、安全监控,机器视觉的应用越来越普遍。如果你对机器视觉感兴趣,想入门这个领域,那么本文将为你提供一份全面的学习指南...

关键字: 机器视觉 人工智能

事件相机是感知“事件”发生变化并输出“事件”信息,有别于传统相机输出的图像信息。而所谓的“事件”指的就是每个像素的亮度变化,输出的也就是像素亮度变化情况。事件相机的关键器件就是基于事件的视觉传感器,简称EVS(Event...

关键字: 事件相机 EVS Prophesee 机器视觉 AI
关闭
关闭