In machine vision processing, we often evaluate the orientation characteristics of the detected objects. For example, we want OCR to recognize a string. Then the angle between this string and the x-axis is very important, we need this information to turn this string right, and then it is easy to identify.
Barcode recognition is similar, especially when our barcodes are not very clear, first correcting the barcode and then processing it with an anisotropic filter to make the barcode clearer and easier to read.
Here is a feature extraction method based on statistical parameters. This method has been around for decades, and it is an old method, but the effect is very good, so it is worth writing an article to introduce.
Moment of the region
The moment of a region R is defined as:
When both p and q take 0, the area of ​​this area is obtained. That is:
The moment can also be normalized, that is, divided by the area a by the above definition.
Indicates the center of gravity of this area. It can be used to describe the location of the area.
The normalized moments vary with the position of the region in the image. To remove this effect, the central moment can be used, and the central moment reflects only the characteristics of the region itself.
The specific method is to treat this area as an elliptical area, then use the above five parameters to calculate the length and rotation angle of the ellipse. The specific formula is as follows:
The graphical interpretation of these parameters of the ellipse is as follows:
Using these parameters, you can determine the orientation and size of the area.
For example, we have the following test image.
The ellipse calculated by the above method is as follows:
It can be seen that the results are very good. Especially the angle of rotation, the calculation is very accurate.
Below is my test code for reference. Used some Qt features.
#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; //the center coordinate of the ellipse x
Double y_mean; //the center coordinate y of the ellipse
Double r1; //The long axis radius of the ellipse
Double r2; //The short axis radius of the ellipse
Double theta; //the angle between the long axis of the ellipse and the x axis (counterclockwise)
};
/**
* @brief ellipseFit Estimate five geometric parameters by treating an area as an ellipse
* @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 = cx();
Double n10 = cy();
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();
}
ZGAR GenkiIppai Pods 5.0
ZGAR electronic cigarette uses high-tech R&D, food grade disposable pod device and high-quality raw material. All package designs are Original IP. Our designer team is from Hong Kong. We have very high requirements for product quality, flavors taste and packaging design. The E-liquid is imported, materials are food grade, and assembly plant is medical-grade dust-free workshops.
From production to packaging, the whole system of tracking, efficient and orderly process, achieving daily efficient output. WEIKA pays attention to the details of each process control. The first class dust-free production workshop has passed the GMP food and drug production standard certification, ensuring quality and safety. We choose the products with a traceability system, which can not only effectively track and trace all kinds of data, but also ensure good product quality.
We offer best price, high quality Pods, Pods Touch Screen, Empty Pod System, Pod Vape, Disposable Pod device, E-cigar, Vape Pods to all over the world.
Much Better Vaping Experience!
ZGAR GenkiIppai 5.0 Pods,ZGAR GenkiIppai Pods 5.0,ZGAR GenkiIppai Pods 5.0 Pod System Vape,ZGAR GenkiIppai Pods 5.0 Disposable Pod Vape Systems, Japanese culture style
ZGAR INTERNATIONAL(HK)CO., LIMITED , https://www.sze-cigarette.com