Commit 81920d8b 张士柳

添加项目文件。

1 个父辈 d730cd33
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
namespace eyemLib_Sharp
{
#region 枚举
//稳健估计方法
public enum ROBUST_METHOD
{
EYEM_DIST_USER = -1,
EYEM_DIST_L1 = 1,
EYEM_DIST_L12 = 2,
EYEM_DIST_FAIR = 3,
EYEM_DIST_WELSCH = 4,
EYEM_DIST_HUBER = 5,
EYEM_DIST_BISQUARE = 6,
EYEM_DIST_CAUCHY = 7,
EYEM_DIST_LOGISTIC = 8,
EYEM_DIST_ANDREWS = 9,
EYEM_DIST_ATLWORTH = 10
}
#endregion
#region 结构体
// 图像信息
[StructLayout(LayoutKind.Sequential)]
public struct EyemImage
{
public IntPtr ucpImage; // 地址
public int iWidth; // 图像内存 x 方向大小
public int iHeight; // 图像内存 y 方向大小
public int iDepth; // 图像通道数
}
// 矩形定义
[StructLayout(LayoutKind.Sequential)]
public struct EyemRect
{
public int iXs; // 起始点(左上角) x 坐标
public int iYs; // 起始点(左上角) y 坐标
public int iWidth; // x 方向大小(宽度)
public int iHeight; // y 方向大小(高度)
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemRect2
{
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iXe; // 端点(右下) x 坐标
int iYe; // 端点(右下) y 坐标
}
///////////////////////////////////////////////////////////////////////////////
// Orthogonal Coordinate System
/////////////////////
// int type
//
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXY
{
int iX; // X坐标
int iY; // Y坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYZ
{
int iX; // X坐标
int iY; // Y坐标
int iZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYQ
{
int iX; // X坐标
int iY; // Y坐标
int iQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYR // 用于表示圆
{
int iX; // X坐标
int iY; // Y坐标
int iR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIABC // 用于表示直线(一般形式)
{
int iA; // a
int iB; // b
int iC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIRQ // 用于表示直线(黑森标准形式)或矢量
{
int iR; // ρ
int iQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsIXYQS
{
int iX; // X坐标(单位:像素)
int iY; // Y坐标(单位:像素)
int iQ; // 斜率(単位:rad)
int iS; // 刻度
}
/////////////////////
// float type
//
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXY
{
float fX; // X坐标
float fY; // Y坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYZ
{
float fX; // X坐标
float fY; // Y坐标
float fZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYQ
{
float fX; // X坐标
float fY; // Y坐标
float fQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYR // 用于表示圆
{
float fX; // X坐标
float fY; // Y坐标
float fR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFABC // 用于表示直线(一般形式)
{
float fA; // a
float fB; // b
float fC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFRQ // 用于表示直线(黑森标准形式)或矢量
{
float fR; // ρ
float fQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsFXYQS
{
float fX; // X坐标(単位:像素)
float fY; // Y坐标(単位:像素)
float fQ; // 斜率(単位:rad)
float fS; // 刻度
}
/////////////////////
// double type
//
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXY
{
public double dX; // X坐标
public double dY; // Y坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYZ
{
double dX; // X坐标
double dY; // Y坐标
double dZ; // Z坐标
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYQ
{
double dX; // X坐标
double dY; // Y坐标
double dQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYR // 用于表示圆
{
double dX; // 中心的X坐标
double dY; // 中心的Y坐标
double dR; // 半径
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDABC // 直线(一般形)的表现形式
{
double dA; // a
double dB; // b
double dC; // c
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDRQ // 直線(ヘッセの標準形)やベクトルの表現に使用
{
double dR; // ρ
double dQ; // θ
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYQS
{
double dX; // X座標
double dY; // Y座標
double dQ; // 回転角(単位:rad)
double dS; // スケール
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDABCD // 平面(一般形)の表現に使用
{
double dA; // a
double dB; // b
double dC; // c
double dD; // d
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDXYLSQ // 楕円の表現に使用
{
double dXo; // 中心のX座標
double dYo; // 中心のY座標
double dL; // 長軸半径
double dS; // 短軸半径
double dQ; // 長軸の傾き(単位:rad)
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDPV // 3次元空間内の直線の表現に使用
{
EyemOcsDXYZ tP; // 直線上の1点の座標
EyemOcsDXYZ tV; // 直線の方向ベクトル
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemOcsDCRUVW // 楕円体の表現に使用
{
EyemOcsDXYZ tC; // 楕円体の中心
EyemOcsDXYZ tR; // 軸の半径(dX:長軸, dY:中軸, dZ:短軸)
double dU; // 長軸のXY平面への射影がX軸となす角(単位:rad)
double dV; // 長軸のXY平面とのなす角(単位:rad)
double dW; // 長軸まわりの回転角(単位:rad)
}
// Blob 分析结果
[StructLayout(LayoutKind.Sequential)]
public struct EyemBinBlob
{
public int iArea; // 面积
public double dCenterX; // 重心x坐标
public double dCenterY; // 重心y坐标
public int iXs, iYs, iXe, iYe; // 外接矩形(始点,终点)
public int iWidth, iHeight; // 外接矩形(x 方向大小(宽度),y 方向大小(高度))
public double dTheta; // 主轴倾斜角(rad)
}
[StructLayout(LayoutKind.Sequential)]
public struct EyemChainCode
{
int iLabel; // 标签
double dX; // x坐标
double dY; // y坐标
double dVx, dVy; // 向量
}
// 条码 解码结果
[StructLayout(LayoutKind.Sequential)]
public struct EyemBarCode
{
public double dAngle; // 角度
public int iCenterX; // x坐标
public int iCenterY; // y坐标
public IntPtr hType; // 码类型
public IntPtr hText; // 码内容
}
#endregion
public unsafe class EyemLib
{
#region 通用
// Win32 memory copy function
[DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern byte* memcpy(byte* dst, byte* src, int count);
//读取图像
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemImageRead(string filename, int iFalgs, out EyemImage ucpImage);
//读取Raw格式图像,仅支持8/16位
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemImageReadRaw(string filename, int iWidth, int iHeight, int iDepth, out EyemImage ucpImage);
//保存图像
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemImageWrite(string filename, EyemImage ipImage);
//释放图像资源
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemImageFree(IntPtr ipImage);
#endregion
#region 2 blob 分析
//二值化图像
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int binMethod, out EyemImage tpDstImg);
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinThreshold(EyemImage tpSrsImg, int iLightDark, int binMethod, out EyemImage tpDstImg);
//Sauvola二值化
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinNiBlack(EyemImage tpSrcImg, out EyemImage tpDstImg, int iType, int iWinSize, double dK, int binarizationMethod, double r);
//动态阈值
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, out EyemImage tpDstImg);
//二值Blob分析
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemBinBlob(EyemImage tpImage, out BlobHandle hObject, int iAreaThrs, out EyemImage tpDstImage, out EyemChainCode* tpContours, out EyemBinBlob* tpResult, out int ipNum);
//释放Blob资源
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern bool eyemBinFree(IntPtr hObject);
#endregion
#region 矩阵运算
//创建二维矩阵
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr eyemMatMallocMatrix(int iRows, int iCols, [In]double[] dpData);
//释放二维矩阵
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemMatFreeMatrix(IntPtr intPtr);
//初始化矩阵
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemMatZero(IntPtr vpA);
//复制矩阵
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemMatCopy(IntPtr vpDst, IntPtr vpSrc);
//矩阵相加
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemMatAdd(IntPtr vpA, IntPtr vpB, IntPtr vpC);
#endregion
#region 一维边缘测量
//边缘测量
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemEdge1dGenMeasureRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, string strSubType, int iTransition, double dSigma, double dAmpThresh, out MeasureHandle hObject);
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
//边缘查找
private static extern int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, out MeasureHandle hObject);
//findLine
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, out MeasureHandle hObject);
//释放工具所使用句柄
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern bool eyemEdge1dGenMeasureFree(IntPtr hObject);
#endregion
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemSkeleton(EyemImage tpImage);
//边缘
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemEdgesPixel(EyemImage tpImage, double dThresh);
#region 稳健估计
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemRobustFitLine(int iPtnNum, IntPtr taPoint, int iCalcMode, double dRobustCoef, ref EyemOcsDABC tpLine);
#endregion
#region 项目
//普通器件
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObject(EyemImage tpImage, string fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, ref string pNumObj, out EyemImage tpDstImg);
//异型器件
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemCountObjectIrregularParts(EyemImage tpImage, string fileName, double dOffset, string strType, int iMaxArea, int iWinSize, ref string pNumObj, out EyemImage tpDstImg);
//读码程序
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, string fileName, string strCodeType, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, bool bUseNiBlack, int iBlockSize, int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
//释放工具所使用句柄
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern bool eyemDetectAndDecodeFree(IntPtr hObject);
#endregion
public static void eyemReadImageTool(string fileName)
{
EyemImage ucpImage;
EyemImage tpDstImg = new EyemImage();
//int flag = eyemImageRead("D:\\图片及统计结果\\图片及统计结果\\data\\6D551\\6D551-R014212020040601587-20200624140637.png", 0, out ucpImage);
//int flag = eyemImageReadRaw(fileName, 3072, 3072, 2, out ucpImage);
int flag = eyemImageRead(fileName, -1, out ucpImage);
if (flag != 0)
{
Console.WriteLine("读图失败!");
return;
}
//ucpImage.iWidth = 3072; ucpImage.iHeight = 3072; ucpImage.iDepth = 2;
//Bitmap bmp = new Bitmap(ucpImage.iWidth, ucpImage.iHeight, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
//ColorPalette color_palette_gray_ = bmp.Palette;
//for (int i = 0; i < 256; i++)
//{
// color_palette_gray_.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
//}
//bmp.Palette = color_palette_gray_;
//BitmapData bdd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
//memcpy((byte*)bdd.Scan0.ToPointer(), (byte*)ucpImage.ucpImage.ToPointer(), bdd.Stride * bdd.Height);
//bmp.UnlockBits(bdd);
//bmp.Dispose();
Stopwatch sw = new Stopwatch();
sw.Restart();
#region Test Blob
//int ipNum;
//BlobHandle hObject;
//EyemBinBlob* eyemBlob;
//EyemChainCode* eyemContours;
//eyemBinBlob(ucpImage, out hObject, 100, out tpDstImg, out eyemContours, out eyemBlob, out ipNum);
//for (int i = 0; i < ipNum; i++)
//{
// tpResult.Add(eyemBlob[i]);
//}
//hObject.Dispose();
#endregion
#region Test 1DEdge
//EyemOcsDXY tpLineSt = new EyemOcsDXY();
//tpLineSt.dX = 947;
//tpLineSt.dY = 1;
//EyemOcsDXY tpLineEd = new EyemOcsDXY();
//tpLineEd.dX = 149;
//tpLineEd.dY = 548;
//MeasureHandle hObject;
//eyemEdge1dGenMeasureRect(ucpImage, tpLineSt, tpLineEd, 10, "all", 0, 0.9, 30, out hObject);
//eyemEdge1dGenPosRect(ucpImage, tpLineSt, tpLineEd, 50, 0, 0.9, 30, out hObject);
//eyemEdge1dFindLine(ucpImage, tpLineSt, tpLineEd, 15, 0, out hObject);
///hObject.Dispose();
#endregion
#region Test Matrix
//double[] dpData = new double[9] { 1, 0, 1, 2, 2, 2, 3, 3, 3 };
//IntPtr vpA = eyemMatMallocMatrix(3, 3, dpData);
//eyemMatZero(vpA);
//double[] dpData2 = new double[9] { 1, 0, 1, 2, 0, 2, 3, 0, 3 };
//IntPtr vpB = eyemMatMallocMatrix(3, 3, dpData);
//IntPtr vpC = IntPtr.Zero;
//eyemMatAdd(vpA, vpB, vpC);
//eyemMatFreeMatrix(vpA);
//eyemMatFreeMatrix(vpB);
#endregion
#region Test Binary
//eyemBinAutoThreshold(ucpImage, 1.8, 1, 6, out tpDstImg);
//eyemSkeleton(ucpImage);
//eyemBinBinaryImage(ucpImage, 0, 3, out tpDtImg);
//eyemBinDynThreshold(ucpImage, ucpImage, 3, 1, out tpDstImg);
//eyemBinNiBlack(ucpImage, out tpDstImg, 0, 11, 0.5, 3, 128);
#endregion
#region Test Sauvola
//eyemBinNiBlack(ucpImage, out tpDstImg, 0, 5, 0.001, 3, 5);
#endregion
#region Test RobustFitLine
//EyemOcsDABC tpLine = new EyemOcsDABC();
//EyemOcsDXY taPoint = new EyemOcsDXY();
//List<EyemOcsDXY> taPoints = new List<EyemOcsDXY>();
//double k = 2.0, b = 1.0;//y=2x+1
//for (int i = 0; i < 100; i += 5)
//{
// taPoint.dX = i;
// taPoint.dY = k * taPoint.dX + b;
// taPoints.Add(taPoint);
//}
//taPoint.dX = 50;
//taPoint.dY = 45;
//taPoints.Add(taPoint);
//taPoint.dX = 60;
//taPoint.dY = 76;
//taPoints.Add(taPoint);
//taPoint.dX = 38;
//taPoint.dY = 58;
//taPoints.Add(taPoint);
//taPoint.dX = 71;
//taPoint.dY = 37;
//taPoints.Add(taPoint);
//taPoint.dX = 15;
//taPoint.dY = 50;
//taPoints.Add(taPoint);
//taPoint.dX = 36;
//taPoint.dY = 56;
//taPoints.Add(taPoint);
//taPoint.dX = 18;
//taPoint.dY = 8;
//taPoints.Add(taPoint);
//taPoint.dX = 100;
//taPoint.dY = 100;
//taPoints.Add(taPoint);
//taPoint.dX = 16;
//taPoint.dY = 16;
//taPoints.Add(taPoint);
//taPoint.dX = 18;
//taPoint.dY = 28;
//taPoints.Add(taPoint);
//taPoint.dX = 17;
//taPoint.dY = 37;
//taPoints.Add(taPoint);
//taPoint.dX = 28;
//taPoint.dY = 48;
//taPoints.Add(taPoint);
//IntPtr tpPoint = teStructArray2IntPtr(taPoints.ToArray(), taPoints.Count);
//eyemRobustFitLine(taPoints.Count, tpPoint, 6, 0, ref tpLine);
//Marshal.FreeHGlobal(tpPoint);
#endregion
#region Test WriteImage
//eyemImageWrite("D:\\Matlab测试图像\\xxx.bmp", tpDstImg);
#endregion
#region Test Edge
//eyemEdgesPixel(ucpImage, 15);
#endregion
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = tpRoi.iYs = 0;
tpRoi.iWidth = ucpImage.iWidth;
tpRoi.iHeight = ucpImage.iHeight;
//
string pNumObj = "";
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
//"IP_SMALL_PARTS","IP_LARGE_PARTS","IP_LONG_PARTS",""
//eyemCountObject(ucpImage, file.Replace(".png", ""), 35, 0, 100, 5, ref pNumObj, out tpDstImg);
//eyemCountObjectIrregularParts(ucpImage, file.Replace(".png", ""), 0d, "IP_LONG_PARTS", 100, 5, ref pNumObj, out tpDstImg);
int ipNum; EyemBarCode* tpResults;
DataCodeHandle hObject;
int iRes = eyemDetectAndDecode(ucpImage, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX|CODE_128|CODE_39", out hObject, out tpResults, out ipNum, false, 11, 5, 128, 215, 1d);
for (int i = 0; i < ipNum; i++)
{
Console.WriteLine("类型:" + Marshal.PtrToStringAnsi(tpResults[i].hType) + ";坐标" + "[" + tpResults[i].iCenterX.ToString() + "," + tpResults[i].iCenterY.ToString() + "]" + ";角度:" + tpResults[i].dAngle.ToString("F4") + "," + ";内容:" + Marshal.PtrToStringAnsi(tpResults[i].hText) + "");
Marshal.FreeCoTaskMem(tpResults[i].hText); Marshal.FreeCoTaskMem(tpResults[i].hType);
}
hObject.Dispose();
sw.Stop();
Console.WriteLine("耗时:" + sw.ElapsedMilliseconds.ToString() + ",结果:" + pNumObj);
//free image
eyemImageFree(ucpImage.ucpImage);
}
//计算最佳参数
public static void eyemReadImageToolTest(string fileName)
{
EyemImage ucpImage;
int flag = eyemImageRead(fileName, -1, out ucpImage);
if (flag != 0)
{
Console.WriteLine("读图失败!");
return;
}
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = tpRoi.iYs = 0;
tpRoi.iWidth = ucpImage.iWidth;
tpRoi.iHeight = ucpImage.iHeight;
//
System.Collections.Generic.Dictionary<int, int> dictPara = new System.Collections.Generic.Dictionary<int, int>();
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
for (int ii = 5; ii < 27; ii += 2)
{
int ipNum; EyemBarCode* tpResults;
DataCodeHandle hObject;
int iRes = eyemDetectAndDecode(ucpImage, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX|CODE_128", out hObject, out tpResults, out ipNum, false, ii, 5, 128, 215, 1d);
dictPara.Add(ii, ipNum);
hObject.Dispose();
//Console.WriteLine("数量:" + ipNum + ";" + "参数:" + ii.ToString());
}
var sortResult = from dic in dictPara orderby dic.Value descending select dic;
foreach (KeyValuePair<int, int> kvp in sortResult)
{
int ipNum; EyemBarCode* tpResults;
DataCodeHandle hObject;
int iRes = eyemDetectAndDecode(ucpImage, tpRoi, file.Replace(".png", ""), "QR_CODE|DATA_MATRIX|CODE_128", out hObject, out tpResults, out ipNum, false, kvp.Key, 5, 128, 215, 1d);
hObject.Dispose();
Console.WriteLine("最佳参数:" + kvp.Key);
break;
}
//free image
eyemImageFree(ucpImage.ucpImage);
return;
}
#region 结构转内存指针
public static IntPtr teStructArray2IntPtr(EyemOcsDXY[] cvPoint2D32f, int iLength)
{
//分配结构体需要的内存
IntPtr ptrTemp = (IntPtr)Marshal.AllocHGlobal(Marshal.SizeOf(typeof(EyemOcsDXY)) * iLength);
for (int j = 0, addr = (int)ptrTemp; j < iLength; j++, addr += Marshal.SizeOf(typeof(EyemOcsDXY)))
{
Marshal.StructureToPtr(cvPoint2D32f[j], (IntPtr)addr, false);
}
return ptrTemp;
}
#endregion
#region 释放句柄
//释放Blob句柄
public class BlobHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public BlobHandle() : base(true) { }
protected override bool ReleaseHandle()
{
return eyemBinFree(handle);
}
}
//释放测量句柄
public class MeasureHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public MeasureHandle() : base(true) { }
protected override bool ReleaseHandle()
{
return eyemEdge1dGenMeasureFree(handle);
}
}
//释放解码句柄
public class DataCodeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public DataCodeHandle() : base(true) { }
protected override bool ReleaseHandle()
{
return eyemDetectAndDecodeFree(handle);
}
}
#endregion
}
}
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
namespace eyemLib_Sharp
{
public unsafe class EyemSamples
{
#region 通用
// Win32 memory copy function
[DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern byte* memcpy(byte* dst, byte* src, int count);
//读取图像
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemImageRead(string filename, int iFalgs, out EyemImage ucpImage);
//保存图像
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemImageWrite(string filename, EyemImage ipImage);
//释放图像资源
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern void eyemImageFree(IntPtr ipImage);
#endregion
//读码程序
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, string fileName, string strCodeType, out DataCodeHandle hObject, out EyemBarCode* tpResults, out int ipNum, bool bUseNiBlack, int iBlockSize, int iRangeC, int iSymbolMin, int iSymbolMax, double dToleErr = 0.5, double dMinorStep = 1.0);
//释放工具
[DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
private static extern bool eyemDetectAndDecodeFree(IntPtr hObject);
public static void eyemReadImageTool(string fileName)
{
EyemImage ucpImage;
int flag = eyemImageRead(fileName, -1, out ucpImage);
if (flag != 0)
{
Console.WriteLine("读图失败!");
return;
}
EyemRect tpRoi = new EyemRect();
tpRoi.iXs = tpRoi.iYs = 0;
tpRoi.iWidth = ucpImage.iWidth;
tpRoi.iHeight = ucpImage.iHeight;
string file = fileName.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries)[2];
int ipNum; EyemBarCode* tpResults;
DataCodeHandle hObject;
eyemDetectAndDecode(ucpImage, tpRoi, file.Replace(".png", ""), "QRCode", out hObject, out tpResults, out ipNum, false, 11, 5, 128, 215);
for (int i = 0; i < ipNum; i++)
{
Console.WriteLine("类型:" + Marshal.PtrToStringAnsi(tpResults[i].hType) + ";坐标" + "[" + tpResults[i].iCenterX.ToString() + "," + tpResults[i].iCenterY.ToString() + "]" + ";内容:" + Marshal.PtrToStringAnsi(tpResults[i].hText) + "");
}
//释放
hObject.Dispose();
//释放图像
eyemImageFree(ucpImage.ucpImage);
}
//释放解码句柄
public class DataCodeHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public DataCodeHandle() : base(true) { }
protected override bool ReleaseHandle()
{
return eyemDetectAndDecodeFree(handle);
}
}
}
}
using System;
using System.IO;
using System.Threading.Tasks;
namespace eyemLib_Sharp
{
class Program
{
static void Main(string[] args)
{
string[] fileNames = Directory.GetFiles(@"D:\批量测试图像\", "*.*", SearchOption.AllDirectories);
//for (int j = 0; j < 100; j++)
//{
// ParallelOptions po = new ParallelOptions();
// po.MaxDegreeOfParallelism = 6;
// Parallel.ForEach(fileNames, po, fn =>
// {
// EyemLib.eyemReadImageTool(fn);
// });
// Console.Clear();
//}
foreach (var fileName in fileNames)
{
EyemLib.eyemReadImageTool(fileName);
//EyemLib.eyemReadImageToolTest(fileName);
}
Console.Write("请按任意键继续。。。");
Console.ReadKey();
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("eyemLib-Sharp")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("eyemLib-Sharp")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//将 ComVisible 设置为 false 将使此程序集中的类型
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("c5284403-d4fd-4d83-bbae-7a4020f1c01f")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>eyemLib_Sharp</RootNamespace>
<AssemblyName>eyemLib-Sharp</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseVSHostingProcess>true</UseVSHostingProcess>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="EyemSamples.cs" />
<Compile Include="EyemLib.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eyemLib", "eyemLib\eyemLib.vcxproj", "{33D5F550-C799-4B05-8E14-ACA390DF5442}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eyemLib-Sharp", "eyemLib-Sharp\eyemLib-Sharp.csproj", "{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}"
ProjectSection(ProjectDependencies) = postProject
{33D5F550-C799-4B05-8E14-ACA390DF5442} = {33D5F550-C799-4B05-8E14-ACA390DF5442}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Debug|Any CPU.ActiveCfg = Debug|Win32
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Debug|x64.ActiveCfg = Debug|x64
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Debug|x64.Build.0 = Debug|x64
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Debug|x86.ActiveCfg = Debug|Win32
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Debug|x86.Build.0 = Debug|Win32
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Release|Any CPU.ActiveCfg = Release|Win32
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Release|x64.ActiveCfg = Release|x64
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Release|x64.Build.0 = Release|x64
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Release|x86.ActiveCfg = Release|Win32
{33D5F550-C799-4B05-8E14-ACA390DF5442}.Release|x86.Build.0 = Release|Win32
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|x64.ActiveCfg = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|x64.Build.0 = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|x86.ActiveCfg = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Debug|x86.Build.0 = Debug|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|Any CPU.Build.0 = Release|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|x64.ActiveCfg = Release|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|x64.Build.0 = Release|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|x86.ActiveCfg = Release|Any CPU
{C5284403-D4FD-4D83-BBAE-7A4020F1C01F}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
/**
* libdmtx - Data Matrix Encoding/Decoding Library
* Copyright 2008, 2009 Mike Laughton. All rights reserved.
*
* See LICENSE file in the main project directory for full
* terms of use and distribution.
*
* Contact: Mike Laughton <mike@dragonflylogic.com>
*
* \file dmtx.h
* \brief Main libdmtx header
*/
#ifndef __DMTX_H__
#define __DMTX_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Time headers required for DmtxTime struct below */
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_PI_2
#define M_PI_2 1.57079632679489661923
#endif
#define DmtxVersion "0.7.4"
#define DmtxUndefined -1
#define DmtxPassFail unsigned int
#define DmtxPass 1
#define DmtxFail 0
#define DmtxBoolean unsigned int
#define DmtxTrue 1
#define DmtxFalse 0
#define DmtxFormatMatrix 0
#define DmtxFormatMosaic 1
#define DmtxSymbolSquareCount 24
#define DmtxSymbolRectCount 6
#define DmtxModuleOff 0x00
#define DmtxModuleOnRed 0x01
#define DmtxModuleOnGreen 0x02
#define DmtxModuleOnBlue 0x04
#define DmtxModuleOnRGB 0x07 /* OnRed | OnGreen | OnBlue */
#define DmtxModuleOn 0x07
#define DmtxModuleUnsure 0x08
#define DmtxModuleAssigned 0x10
#define DmtxModuleVisited 0x20
#define DmtxModuleData 0x40
#define DMTX_CHECK_BOUNDS(l,i) (assert((i) >= 0 && (i) < (l)->length && (l)->length <= (l)->capacity))
typedef enum {
DmtxStatusEncoding, /* Encoding is currently underway */
DmtxStatusComplete, /* Encoding is done and everything went well */
DmtxStatusInvalid, /* Something bad happened that sometimes happens */
DmtxStatusFatal /* Something happened that should never happen */
} DmtxStatus;
typedef enum {
DmtxSchemeAutoFast = -2,
DmtxSchemeAutoBest = -1,
DmtxSchemeAscii = 0,
DmtxSchemeC40,
DmtxSchemeText,
DmtxSchemeX12,
DmtxSchemeEdifact,
DmtxSchemeBase256
} DmtxScheme;
typedef enum {
DmtxSymbolRectAuto = -3,
DmtxSymbolSquareAuto = -2,
DmtxSymbolShapeAuto = -1,
DmtxSymbol10x10 = 0,
DmtxSymbol12x12,
DmtxSymbol14x14,
DmtxSymbol16x16,
DmtxSymbol18x18,
DmtxSymbol20x20,
DmtxSymbol22x22,
DmtxSymbol24x24,
DmtxSymbol26x26,
DmtxSymbol32x32,
DmtxSymbol36x36,
DmtxSymbol40x40,
DmtxSymbol44x44,
DmtxSymbol48x48,
DmtxSymbol52x52,
DmtxSymbol64x64,
DmtxSymbol72x72,
DmtxSymbol80x80,
DmtxSymbol88x88,
DmtxSymbol96x96,
DmtxSymbol104x104,
DmtxSymbol120x120,
DmtxSymbol132x132,
DmtxSymbol144x144,
DmtxSymbol8x18,
DmtxSymbol8x32,
DmtxSymbol12x26,
DmtxSymbol12x36,
DmtxSymbol16x36,
DmtxSymbol16x48
} DmtxSymbolSize;
typedef enum {
DmtxDirNone = 0x00,
DmtxDirUp = 0x01 << 0,
DmtxDirLeft = 0x01 << 1,
DmtxDirDown = 0x01 << 2,
DmtxDirRight = 0x01 << 3,
DmtxDirHorizontal = DmtxDirLeft | DmtxDirRight,
DmtxDirVertical = DmtxDirUp | DmtxDirDown,
DmtxDirRightUp = DmtxDirRight | DmtxDirUp,
DmtxDirLeftDown = DmtxDirLeft | DmtxDirDown
} DmtxDirection;
typedef enum {
DmtxSymAttribSymbolRows,
DmtxSymAttribSymbolCols,
DmtxSymAttribDataRegionRows,
DmtxSymAttribDataRegionCols,
DmtxSymAttribHorizDataRegions,
DmtxSymAttribVertDataRegions,
DmtxSymAttribMappingMatrixRows,
DmtxSymAttribMappingMatrixCols,
DmtxSymAttribInterleavedBlocks,
DmtxSymAttribBlockErrorWords,
DmtxSymAttribBlockMaxCorrectable,
DmtxSymAttribSymbolDataWords,
DmtxSymAttribSymbolErrorWords,
DmtxSymAttribSymbolMaxCorrectable
} DmtxSymAttribute;
typedef enum {
DmtxCorner00 = 0x01 << 0,
DmtxCorner10 = 0x01 << 1,
DmtxCorner11 = 0x01 << 2,
DmtxCorner01 = 0x01 << 3
} DmtxCornerLoc;
typedef enum {
/* Encoding properties */
DmtxPropScheme = 100,
DmtxPropSizeRequest,
DmtxPropMarginSize,
DmtxPropModuleSize,
/* Decoding properties */
DmtxPropEdgeMin = 200,
DmtxPropEdgeMax,
DmtxPropScanGap,
DmtxPropSquareDevn,
DmtxPropSymbolSize,
DmtxPropEdgeThresh,
/* Image properties */
DmtxPropWidth = 300,
DmtxPropHeight,
DmtxPropPixelPacking,
DmtxPropBitsPerPixel,
DmtxPropBytesPerPixel,
DmtxPropRowPadBytes,
DmtxPropRowSizeBytes,
DmtxPropImageFlip,
DmtxPropChannelCount,
/* Image modifiers */
DmtxPropXmin = 400,
DmtxPropXmax,
DmtxPropYmin,
DmtxPropYmax,
DmtxPropScale
} DmtxProperty;
typedef enum {
/* Custom format */
DmtxPackCustom = 100,
/* 1 bpp */
DmtxPack1bppK = 200,
/* 8 bpp grayscale */
DmtxPack8bppK = 300,
/* 16 bpp formats */
DmtxPack16bppRGB = 400,
DmtxPack16bppRGBX,
DmtxPack16bppXRGB,
DmtxPack16bppBGR,
DmtxPack16bppBGRX,
DmtxPack16bppXBGR,
DmtxPack16bppYCbCr,
/* 24 bpp formats */
DmtxPack24bppRGB = 500,
DmtxPack24bppBGR,
DmtxPack24bppYCbCr,
/* 32 bpp formats */
DmtxPack32bppRGBX = 600,
DmtxPack32bppXRGB,
DmtxPack32bppBGRX,
DmtxPack32bppXBGR,
DmtxPack32bppCMYK
} DmtxPackOrder;
typedef enum {
DmtxFlipNone = 0x00,
DmtxFlipX = 0x01 << 0,
DmtxFlipY = 0x01 << 1
} DmtxFlip;
typedef double DmtxMatrix3[3][3];
/**
* @struct DmtxPixelLoc
* @brief DmtxPixelLoc
*/
typedef struct DmtxPixelLoc_struct {
int X;
int Y;
} DmtxPixelLoc;
/**
* @struct DmtxVector2
* @brief DmtxVector2
*/
typedef struct DmtxVector2_struct {
double X;
double Y;
} DmtxVector2;
/**
* @struct DmtxRay2
* @brief DmtxRay2
*/
typedef struct DmtxRay2_struct {
double tMin;
double tMax;
DmtxVector2 p;
DmtxVector2 v;
} DmtxRay2;
typedef unsigned char DmtxByte;
/**
* @struct DmtxByteList
* @brief DmtxByteList
* Use signed int for length fields instead of size_t to play nicely with RS
* arithmetic
*/
typedef struct DmtxByteList_struct DmtxByteList;
struct DmtxByteList_struct
{
int length;
int capacity;
DmtxByte *b;
};
typedef struct DmtxEncodeStream_struct DmtxEncodeStream;
struct DmtxEncodeStream_struct
{
int currentScheme; /* Current encodation scheme */
int inputNext; /* Index of next unprocessed input word in queue */
int outputChainValueCount; /* Count of output values pushed within current scheme chain */
int outputChainWordCount; /* Count of output words pushed within current scheme chain */
char *reason; /* Reason for status */
int sizeIdx; /* Symbol size of completed stream */
DmtxStatus status;
DmtxByteList *input;
DmtxByteList *output;
};
/**
* @struct DmtxImage
* @brief DmtxImage
*/
typedef struct DmtxImage_struct {
int width;
int height;
int pixelPacking;
int bitsPerPixel;
int bytesPerPixel;
int rowPadBytes;
int rowSizeBytes;
int imageFlip;
int channelCount;
int channelStart[4];
int bitsPerChannel[4];
unsigned char *pxl;
} DmtxImage;
/**
* @struct DmtxPointFlow
* @brief DmtxPointFlow
*/
typedef struct DmtxPointFlow_struct {
int plane;
int arrive;
int depart;
int mag;
DmtxPixelLoc loc;
} DmtxPointFlow;
/**
* @struct DmtxBestLine
* @brief DmtxBestLine
*/
typedef struct DmtxBestLine_struct {
int angle;
int hOffset;
int mag;
int stepBeg;
int stepPos;
int stepNeg;
int distSq;
double devn;
DmtxPixelLoc locBeg;
DmtxPixelLoc locPos;
DmtxPixelLoc locNeg;
} DmtxBestLine;
/**
* @struct DmtxRegion
* @brief DmtxRegion
*/
typedef struct DmtxRegion_struct {
/* Trail blazing values */
int jumpToPos; /* */
int jumpToNeg; /* */
int stepsTotal; /* */
DmtxPixelLoc finalPos; /* */
DmtxPixelLoc finalNeg; /* */
DmtxPixelLoc boundMin; /* */
DmtxPixelLoc boundMax; /* */
DmtxPointFlow flowBegin; /* */
/* Orientation values */
int polarity; /* */
int stepR;
int stepT;
DmtxPixelLoc locR; /* remove if stepR works above */
DmtxPixelLoc locT; /* remove if stepT works above */
/* Region fitting values */
int leftKnown; /* known == 1; unknown == 0 */
int leftAngle; /* hough angle of left edge */
DmtxPixelLoc leftLoc; /* known (arbitrary) location on left edge */
DmtxBestLine leftLine; /* */
int bottomKnown; /* known == 1; unknown == 0 */
int bottomAngle; /* hough angle of bottom edge */
DmtxPixelLoc bottomLoc; /* known (arbitrary) location on bottom edge */
DmtxBestLine bottomLine; /* */
int topKnown; /* known == 1; unknown == 0 */
int topAngle; /* hough angle of top edge */
DmtxPixelLoc topLoc; /* known (arbitrary) location on top edge */
int rightKnown; /* known == 1; unknown == 0 */
int rightAngle; /* hough angle of right edge */
DmtxPixelLoc rightLoc; /* known (arbitrary) location on right edge */
/* Region calibration values */
int onColor; /* */
int offColor; /* */
int sizeIdx; /* Index of arrays that store Data Matrix constants */
int symbolRows; /* Number of total rows in symbol including alignment patterns */
int symbolCols; /* Number of total columns in symbol including alignment patterns */
int mappingRows; /* Number of data rows in symbol */
int mappingCols; /* Number of data columns in symbol */
/* Transform values */
DmtxMatrix3 raw2fit; /* 3x3 transformation from raw image to fitted barcode grid */
DmtxMatrix3 fit2raw; /* 3x3 transformation from fitted barcode grid to raw image */
} DmtxRegion;
/**
* @struct DmtxMessage
* @brief DmtxMessage
*/
typedef struct DmtxMessage_struct {
size_t arraySize; /* mappingRows * mappingCols */
size_t codeSize; /* Size of encoded data (data words + error words) */
size_t outputSize; /* Size of buffer used to hold decoded data */
int outputIdx; /* Internal index used to store output progress */
int padCount;
unsigned char *array; /* Pointer to internal representation of Data Matrix modules */
unsigned char *code; /* Pointer to internal storage of code words (data and error) */
unsigned char *output; /* Pointer to internal storage of decoded output */
} DmtxMessage;
/**
* @struct DmtxScanGrid
* @brief DmtxScanGrid
*/
typedef struct DmtxScanGrid_struct {
/* set once */
int minExtent; /* Smallest cross size used in scan */
int maxExtent; /* Size of bounding grid region (2^N - 1) */
int xOffset; /* Offset to obtain image X coordinate */
int yOffset; /* Offset to obtain image Y coordinate */
int xMin; /* Minimum X in image coordinate system */
int xMax; /* Maximum X in image coordinate system */
int yMin; /* Minimum Y in image coordinate system */
int yMax; /* Maximum Y in image coordinate system */
/* reset for each level */
int total; /* Total number of crosses at this size */
int extent; /* Length/width of cross in pixels */
int jumpSize; /* Distance in pixels between cross centers */
int pixelTotal; /* Total pixel count within an individual cross path */
int startPos; /* X and Y coordinate of first cross center in pattern */
/* reset for each cross */
int pixelCount; /* Progress (pixel count) within current cross pattern */
int xCenter; /* X center of current cross pattern */
int yCenter; /* Y center of current cross pattern */
} DmtxScanGrid;
/**
* @struct DmtxTime
* @brief DmtxTime
*/
typedef struct DmtxTime_struct {
time_t sec;
unsigned long usec;
} DmtxTime;
/**
* @struct DmtxDecode
* @brief DmtxDecode
*/
typedef struct DmtxDecode_struct {
/* Options */
int edgeMin;
int edgeMax;
int scanGap;
double squareDevn;
int sizeIdxExpected;
int edgeThresh;
/* Image modifiers */
int xMin;
int xMax;
int yMin;
int yMax;
int scale;
/* Internals */
/* int cacheComplete; */
unsigned char *cache;
DmtxImage *image;
DmtxScanGrid grid;
} DmtxDecode;
/**
* @struct DmtxEncode
* @brief DmtxEncode
*/
typedef struct DmtxEncode_struct {
int method;
int scheme;
int sizeIdxRequest;
int marginSize;
int moduleSize;
int pixelPacking;
int imageFlip;
int rowPadBytes;
DmtxMessage *message;
DmtxImage *image;
DmtxRegion region;
DmtxMatrix3 xfrm; /* XXX still necessary? */
DmtxMatrix3 rxfrm; /* XXX still necessary? */
} DmtxEncode;
/**
* @struct DmtxChannel
* @brief DmtxChannel
*/
typedef struct DmtxChannel_struct {
int encScheme; /* current encodation scheme */
int invalid; /* channel status (invalid if non-zero) */
unsigned char *inputPtr; /* pointer to current input character */
unsigned char *inputStop; /* pointer to position after final input character */
int encodedLength; /* encoded length (units of 2/3 bits) */
int currentLength; /* current length (units of 2/3 bits) */
int firstCodeWord; /* */
unsigned char encodedWords[1558];
} DmtxChannel;
/* Wrap in a struct for fast copies */
/**
* @struct DmtxChannelGroup
* @brief DmtxChannelGroup
*/
typedef struct DmtxChannelGroup_struct {
DmtxChannel channel[6];
} DmtxChannelGroup;
/**
* @struct DmtxTriplet
* @brief DmtxTriplet
*/
typedef struct DmtxTriplet_struct {
unsigned char value[3];
} DmtxTriplet;
/**
* @struct DmtxQuadruplet
* @brief DmtxQuadruplet
*/
typedef struct DmtxQuadruplet_struct {
unsigned char value[4];
} DmtxQuadruplet;
/* dmtxtime.c */
extern DmtxTime dmtxTimeNow(void);
extern DmtxTime dmtxTimeAdd(DmtxTime t, long msec);
extern int dmtxTimeExceeded(DmtxTime timeout);
/* dmtxencode.c */
extern DmtxEncode *dmtxEncodeCreate(void);
extern DmtxPassFail dmtxEncodeDestroy(DmtxEncode **enc);
extern DmtxPassFail dmtxEncodeSetProp(DmtxEncode *enc, int prop, int value);
extern int dmtxEncodeGetProp(DmtxEncode *enc, int prop);
extern DmtxPassFail dmtxEncodeDataMatrix(DmtxEncode *enc, int n, unsigned char *s);
extern DmtxPassFail dmtxEncodeDataMosaic(DmtxEncode *enc, int n, unsigned char *s);
/* dmtxdecode.c */
extern DmtxDecode *dmtxDecodeCreate(DmtxImage *img, int scale);
extern DmtxPassFail dmtxDecodeDestroy(DmtxDecode **dec);
extern DmtxPassFail dmtxDecodeSetProp(DmtxDecode *dec, int prop, int value);
extern int dmtxDecodeGetProp(DmtxDecode *dec, int prop);
extern /*@exposed@*/ unsigned char *dmtxDecodeGetCache(DmtxDecode *dec, int x, int y);
extern DmtxPassFail dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, /*@out@*/ int *value);
extern DmtxMessage *dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix);
extern DmtxMessage *dmtxDecodeMosaicRegion(DmtxDecode *dec, DmtxRegion *reg, int fix);
extern unsigned char *dmtxDecodeCreateDiagnostic(DmtxDecode *dec, /*@out@*/ int *totalBytes, /*@out@*/ int *headerBytes, int style);
/* dmtxregion.c */
extern DmtxRegion *dmtxRegionCreate(DmtxRegion *reg);
extern DmtxPassFail dmtxRegionDestroy(DmtxRegion **reg);
extern DmtxRegion *dmtxRegionFindNext(DmtxDecode *dec, DmtxTime *timeout);
extern DmtxRegion *dmtxRegionScanPixel(DmtxDecode *dec, int x, int y);
extern DmtxPassFail dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00,
DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01);
extern DmtxPassFail dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg);
/* dmtxmessage.c */
extern DmtxMessage *dmtxMessageCreate(int sizeIdx, int symbolFormat);
extern DmtxPassFail dmtxMessageDestroy(DmtxMessage **msg);
/* dmtximage.c */
extern DmtxImage *dmtxImageCreate(unsigned char *pxl, int width, int height, int pack);
extern DmtxPassFail dmtxImageDestroy(DmtxImage **img);
extern DmtxPassFail dmtxImageSetChannel(DmtxImage *img, int channelStart, int bitsPerChannel);
extern DmtxPassFail dmtxImageSetProp(DmtxImage *img, int prop, int value);
extern int dmtxImageGetProp(DmtxImage *img, int prop);
extern int dmtxImageGetByteOffset(DmtxImage *img, int x, int y);
extern DmtxPassFail dmtxImageGetPixelValue(DmtxImage *img, int x, int y, int channel, /*@out@*/ int *value);
extern DmtxPassFail dmtxImageSetPixelValue(DmtxImage *img, int x, int y, int channel, int value);
extern DmtxBoolean dmtxImageContainsInt(DmtxImage *img, int margin, int x, int y);
extern DmtxBoolean dmtxImageContainsFloat(DmtxImage *img, double x, double y);
/* dmtxvector2.c */
extern DmtxVector2 *dmtxVector2AddTo(DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2Add(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2SubFrom(DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2Sub(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2ScaleBy(DmtxVector2 *v, double s);
extern DmtxVector2 *dmtxVector2Scale(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v, double s);
extern double dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2);
extern double dmtxVector2Norm(DmtxVector2 *v);
extern double dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2);
extern double dmtxVector2Mag(const DmtxVector2 *v);
extern double dmtxDistanceFromRay2(const DmtxRay2 *r, const DmtxVector2 *q);
extern double dmtxDistanceAlongRay2(const DmtxRay2 *r, const DmtxVector2 *q);
extern DmtxPassFail dmtxRay2Intersect(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1);
extern DmtxPassFail dmtxPointAlongRay2(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *r, double t);
/* dmtxmatrix3.c */
extern void dmtxMatrix3Copy(/*@out@*/ DmtxMatrix3 m0, DmtxMatrix3 m1);
extern void dmtxMatrix3Identity(/*@out@*/ DmtxMatrix3 m);
extern void dmtxMatrix3Translate(/*@out@*/ DmtxMatrix3 m, double tx, double ty);
extern void dmtxMatrix3Rotate(/*@out@*/ DmtxMatrix3 m, double angle);
extern void dmtxMatrix3Scale(/*@out@*/ DmtxMatrix3 m, double sx, double sy);
extern void dmtxMatrix3Shear(/*@out@*/ DmtxMatrix3 m, double shx, double shy);
extern void dmtxMatrix3LineSkewTop(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewTopInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewSide(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewSideInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3Multiply(/*@out@*/ DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1);
extern void dmtxMatrix3MultiplyBy(DmtxMatrix3 m0, DmtxMatrix3 m1);
extern int dmtxMatrix3VMultiply(/*@out@*/ DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m);
extern int dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m);
extern void dmtxMatrix3Print(DmtxMatrix3 m);
/* dmtxsymbol.c */
extern int dmtxSymbolModuleStatus(DmtxMessage *mapping, int sizeIdx, int row, int col);
extern int dmtxGetSymbolAttribute(int attribute, int sizeIdx);
extern int dmtxGetBlockDataSize(int sizeIdx, int blockIdx);
/* dmtxbytelist.c */
extern DmtxByteList dmtxByteListBuild(DmtxByte *storage, int capacity);
extern void dmtxByteListInit(DmtxByteList *list, int length, DmtxByte value, DmtxPassFail *passFail);
extern void dmtxByteListClear(DmtxByteList *list);
extern DmtxBoolean dmtxByteListHasCapacity(DmtxByteList *list);
extern void dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail);
extern void dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail);
extern DmtxByte dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail);
extern void dmtxByteListPrint(DmtxByteList *list, char *prefix);
extern char *dmtxVersion(void);
#ifdef __cplusplus
}
#endif
#endif
#include "eyemBarCode.h"
static cv::Mat getQRRegion(cv::Mat src, cv::RotatedRect rect, double angle)
{
cv::Point center = rect.center;
// 获得左上角和右下角的角点,而且要保证不超出图片范围,用于抠图
cv::Point TopLeft = cv::Point(cvRound(center.x), cvRound(center.y)) - cv::Point(cvRound(rect.size.height / 2), cvRound(rect.size.width / 2));
TopLeft.x = TopLeft.x > src.cols ? src.cols : TopLeft.x;
TopLeft.x = TopLeft.x < 0 ? 0 : TopLeft.x;
TopLeft.y = TopLeft.y > src.rows ? src.rows : TopLeft.y;
TopLeft.y = TopLeft.y < 0 ? 0 : TopLeft.y;
int after_width, after_height;
if (TopLeft.x + rect.size.width > src.cols) {
after_width = src.cols - TopLeft.x - 1;
}
else {
after_width = cvRound(rect.size.width) - 1;
}
if (TopLeft.y + rect.size.height > src.rows) {
after_height = src.rows - TopLeft.y - 1;
}
else {
after_height = cvRound(rect.size.height) - 1;
}
// 获得二维码的位置
cv::Rect RoiRect = cv::Rect(TopLeft.x, TopLeft.y, after_width, after_height);
// dst是被旋转的图片,roi为输出图片,mask为掩模
cv::Mat mask, roi, dst;
cv::Mat image;
// 建立中介图像辅助处理图像
std::vector<cv::Point> contour;
// 获得矩形的四个点
cv::Point2f points[4];
rect.points(points);
for (int i = 0; i < 4; i++)
contour.push_back(points[i]);
std::vector<std::vector<cv::Point>> contours;
contours.push_back(contour);
// 再中介图像中画出轮廓
drawContours(mask, contours, 0, cv::Scalar(255, 255, 255), -1);
// 通过mask掩膜将src中特定位置的像素拷贝到dst中。
src.copyTo(dst, mask);
// 旋转
cv::Mat M = getRotationMatrix2D(center, angle, 1);
warpAffine(dst, image, M, src.size());
// 截图
return image(RoiRect);
}
static void split(const std::string &cStrText, const std::string &cStrDelim, std::vector<std::string> &vStrs)
{
char *cpStr = new char[strlen(cStrText.c_str()) + 1];
strcpy(cpStr, cStrText.c_str());
//分割
char *token = NULL, *ptr = NULL;
token = strtok_s(cpStr, cStrDelim.c_str(), &ptr);
while (NULL != token)
{
vStrs.push_back(token);
token = strtok_s(NULL, cStrDelim.c_str(), &ptr);
}
delete[] cpStr;
cpStr = NULL;
}
static void filterByApriltag(cv::Mat &binary, cv::Mat &labels, std::vector<tMap> &vPts, std::vector<uchar> &colors, int nccomps, double dToleErr = 0.5)
{
//图像尺寸
int X = binary.cols, Y = binary.rows;
//背景
colors[0] = 255;
std::vector<tMap> temp;
//水平扫描
for (int c = 0; c < (int)vPts.size(); c++)
{
const uint8_t *ptrRow = binary.ptr<uint8_t>(vPts[c].Pt.y);
//当前可能不是二维码区域
if (ptrRow[vPts[c].Pt.x] == 0 || ptrRow[std::min(vPts[c].Pt.x + 1, X)] == 0 || ptrRow[std::max(vPts[c].Pt.x - 1, 0)] == 0 || \
binary.ptr<uint8_t>(std::max(vPts[c].Pt.y - 1, 0))[vPts[c].Pt.x] == 0 || binary.ptr<uint8_t>(std::min(vPts[c].Pt.y + 1, Y))[vPts[c].Pt.x] == 0)
{
colors[vPts[c].Label] = 0;
continue;
}
uint8_t future_pixel_right = 255;
uint8_t next_pixel;
//终止条件
int flags = 0;
double test_line[6]{ 0 };//0 中间那块;1那两块黑色;2外圈那两块
//向右扫描
for (int x = vPts[c].Pt.x + 1; x < X - 1; x++)
{
//colors为0的不参与统计
if ((colors[labels.ptr<int>(vPts[c].Pt.y)[x]] == 0))
{
continue;
}
next_pixel = ptrRow[x];
//统计黑白像素
test_line[flags]++;
if (next_pixel != future_pixel_right)
{
flags++;
future_pixel_right = 255 - future_pixel_right;
if (flags == 3) { break; }
}
}
uint8_t future_pixel_left = 255;
//向左扫描
for (int x = vPts[c].Pt.x - 1; x >= 1; x--)
{
//colors为0的不参与统计
if ((colors[labels.ptr<int>(vPts[c].Pt.y)[x]] == 0))
{
continue;
}
next_pixel = ptrRow[x];
//统计黑白像素
test_line[flags]++;
if (next_pixel != future_pixel_left)
{
flags++;
future_pixel_left = 255 - future_pixel_left;
if (flags == 6) { break; };
}
}
//判断是否符合条件,[1]/[4]为1:1------[2]/[5]为1:1-----([1]+[4])/([0]+[3])-----约为0.67
double rate = cv::min(test_line[1], test_line[4]) / cv::max(test_line[1], test_line[4]);
if ((rate >= (1. - dToleErr) && rate <= (1. + dToleErr)))
{
rate = cv::min(test_line[2], test_line[5]) / cv::max(test_line[2], test_line[5]);
if ((rate >= (1. - dToleErr) && rate <= (1. + dToleErr)))
{
rate = (test_line[1] + test_line[4]) / (test_line[0] + test_line[3]);
//允许50%的误差
if (rate >= ((2. / 3.)*(1. - dToleErr)) && rate <= ((2. / 3.)*(1. + dToleErr)))
{
temp.push_back(vPts[c]);
}
else
{
colors[vPts[c].Label] = 0;
}
}
else
{
colors[vPts[c].Label] = 0;
}
}
else
{
colors[vPts[c].Label] = 0;
}
}
//垂直扫描
for (int c = 0; c < (int)temp.size(); c++)
{
uint8_t future_pixel_down = 255;
uint8_t next_pixel;
//终止条件
int flags = 0;
double test_line[6]{ 0 };
//向下扫描
for (int y = temp[c].Pt.y + 1; y < Y - 1; y++)
{
//colors为0的不参与统计
if ((colors[labels.ptr<int>(y)[temp[c].Pt.x]] == 0))
{
continue;
}
next_pixel = binary.ptr<uint8_t>(y)[temp[c].Pt.x];
//统计黑白像素
test_line[flags]++;
if (next_pixel != future_pixel_down)
{
flags++;
future_pixel_down = 255 - future_pixel_down;
if (flags == 3) { break; };
}
}
uint8_t future_pixel_up = 255;
//向下扫描
for (int y = temp[c].Pt.y - 1; y >= 1; y--)
{
//colors为0的不参与统计
if ((colors[labels.ptr<int>(y)[temp[c].Pt.x]] == 0))
{
continue;
}
next_pixel = binary.ptr<uint8_t>(y)[temp[c].Pt.x];
//统计黑白像素
test_line[flags]++;
if (next_pixel != future_pixel_up)
{
flags++;
future_pixel_up = 255 - future_pixel_up;
if (flags == 6) { break; };
}
}
//判断是否符合条件,[1]/[4]为1:1------[2]/[5]为1:1-----([1]+[4])/([0]+[3])-----约为0.67
double rate = cv::min(test_line[1], test_line[4]) / cv::max(test_line[1], test_line[4]);
if (rate >= (1. - dToleErr) && rate <= (1 + dToleErr))
{
rate = cv::min(test_line[2], test_line[5]) / cv::max(test_line[2], test_line[5]);
if (rate >= (1. - dToleErr) && rate <= (1 + dToleErr))
{
rate = (test_line[1] + test_line[4]) / (test_line[0] + test_line[3]);
//允许50%的误差
if (rate >= ((2. / 3.)*(1. - dToleErr)) && rate <= ((2. / 3.)*(1. + dToleErr)))
{
//大部分条件均满足,进入候选点
}
else
{
colors[temp[c].Label] = 0;
}
}
else
{
colors[temp[c].Label] = 0;
}
}
else
{
colors[temp[c].Label] = 0;
}
}
colors[0] = 0;
//过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = binary.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
}
static double getThreshVal_Otsu_8u(const cv::Mat& _src)
{
cv::Size size = _src.size();
int step = (int)_src.step;
if (_src.isContinuous())
{
size.width *= size.height;
size.height = 1;
step = size.width;
}
#ifdef HAVE_IPP
unsigned char thresh = 0;
CV_IPP_RUN_FAST(ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
#endif
const int N = 256;
int i, j, h[N] = { 0 };
#if CV_ENABLE_UNROLLED
int h_unrolled[3][N] = {};
#endif
for (i = 0; i < size.height; i++)
{
const uchar* src = _src.ptr() + step*i;
j = 0;
#if CV_ENABLE_UNROLLED
for (; j <= size.width - 4; j += 4)
{
int v0 = src[j], v1 = src[j + 1];
h[v0]++; h_unrolled[0][v1]++;
v0 = src[j + 2]; v1 = src[j + 3];
h_unrolled[1][v0]++; h_unrolled[2][v1]++;
}
#endif
for (; j < size.width; j++)
h[src[j]]++;
}
double mu = 0, scale = 1. / (size.width*size.height);
for (i = 0; i < N; i++)
{
#if CV_ENABLE_UNROLLED
h[i] += h_unrolled[0][i] + h_unrolled[1][i] + h_unrolled[2][i];
#endif
mu += i*(double)h[i];
}
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for (i = 0; i < N; i++)
{
double p_i, q2, mu2, sigma;
p_i = h[i] * scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if (std::min(q1, q2) < FLT_EPSILON || std::max(q1, q2) > 1. - FLT_EPSILON)
continue;
mu1 = (mu1 + i*p_i) / q1;
mu2 = (mu - q1*mu1) / q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
if (sigma > max_sigma)
{
max_sigma = sigma;
max_val = i;
}
}
return max_val;
}
static void decodeMul(std::vector<WaitArea> &waitAreas, std::vector<std::string> &hints, cv::Mat &showMat, std::vector<DecodeResult> &decodeResults, int iBlockSize, const int iRangeC, double dMinorStep)
{
//进入线程锁
mtx.lock();
//处理解码
for (int i = 0; i < waitAreas.size(); i++)
{
bool bDecode = false;
//解码结果
std::string strResult = ""; std::string strResultType = ""; cv::Point ptResult = cv::Point();
//优先当作DM来解码,因为它比较快
if (!waitAreas[i].oneD)
{
DmtxMessage *msg;
DmtxRegion *reg;
DmtxImage *img = dmtxImageCreate(waitAreas[i].waitArea.data, waitAreas[i].waitArea.cols, waitAreas[i].waitArea.rows, DmtxPack8bppK);
DmtxDecode *dec = dmtxDecodeCreate(img, 1);
//超时
DmtxTime beginTime = dmtxTimeNow();
DmtxTime timeout = dmtxTimeAdd(beginTime, 25);
reg = dmtxRegionFindNext(dec, &timeout);
if (NULL != reg)
{
//解码
msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined);
if (NULL != msg)
{
bDecode = true;
ptResult = waitAreas[i].Pt;
strResultType = "DATA_MATRIX";
strResult = std::string(reinterpret_cast<const char *>(msg->output));
//销毁资源
dmtxMessageDestroy(&msg);
}
//解码失败
dmtxRegionDestroy(&reg);
}
dmtxDecodeDestroy(&dec);
dmtxImageDestroy(&img);
}
//如果未解码,判断可能是QR或者一维码或者DATA_MATRIX
if (!bDecode)
{
if (waitAreas[i].oneD)
{
//创建解码器
Ref<Reader> reader_;
reader_.reset(Ref<Reader>(new zxing::oned::MultiFormatOneDReader(DecodeHints::CODE_128_HINT | DecodeHints::CODE_39_HINT)));
//一维码识别
for (int ii = 0; ii < waitAreas[i].oneDMats.size(); ii++)
{
cv::Mat src = waitAreas[i].oneDMats[ii];
cv::pyrUp(src, src, cv::Size(src.cols * 2, src.rows * 2));
//判断解码结果
double threshVal = getThreshVal_Otsu_8u(src);
for (double c = threshVal - 4 * iRangeC; c < threshVal + 4 * iRangeC; c += dMinorStep)
{
cv::Mat binary;
cv::threshold(src, binary, c, 255, cv::THRESH_BINARY);
try
{
//创建图像
Ref<LuminanceSource> source = MatSource::create(binary);
Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
//解码
Ref<Result> result(reader_->decode(bitmap, DecodeHints::CODE_128_HINT | DecodeHints::CODE_39_HINT));
if (!result.empty())
{
bDecode = true;
ptResult = waitAreas[i].Pt;
strResult = result->getText()->getText();
switch (result->getBarcodeFormat())
{
case NONE:
strResultType = "NONE";
break;
case CODABAR:
strResultType = "CODABAR";
break;
case CODE_39:
strResultType = "CODE_39";
break;
case CODE_93:
strResultType = "CODE_93";
break;
case CODE_128:
strResultType = "CODE_128";
break;
case EAN_8:
strResultType = "EAN_8";
case EAN_13:
strResultType = "EAN_13";
break;
case ITF:
strResultType = "ITF";
break;
case MAXICODE:
strResultType = "MAXICODE";
break;
case RSS_14:
strResultType = "RSS_14";
break;
case RSS_EXPANDED:
strResultType = "RSS_EXPANDED";
break;
case UPC_A:
strResultType = "UPC_A";
break;
case UPC_E:
strResultType = "UPC_E";
break;
case UPC_EAN_EXTENSION:
strResultType = "UPC_EAN_EXTENSION";
break;
default:
break;
}
}
}
catch (...) {
//there is something wrong
}
}
if (bDecode) {
break;
}
}
if (!bDecode)
{
//如果仍未解码
}
}
else
{
//添加二维码解码器
std::vector<Ref<Reader>> readers_;
if (std::find(hints.begin(), hints.end(), "QR_CODE") != hints.end()) {
readers_.push_back(Ref<Reader>(new zxing::qrcode::QRCodeReader));
}
if (std::find(hints.begin(), hints.end(), "DATA_MATRIX") != hints.end()) {
readers_.push_back(Ref<Reader>(new zxing::datamatrix::DataMatrixReader));
}
if (std::find(hints.begin(), hints.end(), "AZTEC") != hints.end()) {
readers_.push_back(Ref<Reader>(new zxing::aztec::AztecReader));
}
cv::Mat binary;
cv::Mat src = waitAreas[i].waitArea;
for (unsigned int ii = 0; ii < readers_.size(); ii++) {
//尝试多种参数解码
for (int blockSize = iBlockSize - 2; blockSize <= iBlockSize + 2; blockSize += 2)
{
for (double d = waitAreas[i].C - (double)iRangeC; d <= waitAreas[i].C + (double)iRangeC; d += dMinorStep)
{
cv::adaptiveThreshold(src, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, blockSize, d);
try {
//创建图像
Ref<LuminanceSource> source = MatSource::create(binary);
Ref<Binarizer> binarizer(new GlobalHistogramBinarizer(source));
Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));
Ref<Result> result(readers_[ii]->decode(bitmap, zxing::DecodeHints::TRYHARDER_HINT));
//如果解码成功
if (!result.empty())
{
ptResult = waitAreas[i].Pt;
strResult = result->getText()->getText();
switch (result->getBarcodeFormat())
{
case AZTEC:
strResultType = "AZTEC";
break;
case DATA_MATRIX:
strResultType = "DATA_MATRIX";
break;
case QR_CODE:
strResultType = "QR_CODE";
break;
default:
break;
}
goto breakLoop;
}
}
catch (...) {
//there is something wrong
}
}
}
}
breakLoop:
{
if (strResult != std::string())
{
bDecode = true;
}
}
}
}
//判断是否解码
if (bDecode)
{
decodeResults.push_back(DecodeResult(waitAreas[i].angle, ptResult, strResult, strResultType));
cv::putText(showMat, strResult, ptResult, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
}
}
//离开线程锁
mtx.unlock();
}
int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **hResults, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown, double dToleErr, double dMinorStep)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, tpImage.iDepth, tpImage.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
//提取ROI
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight));
//图像原图备份
cv::Mat backup = src.clone();
//降采样
if (dScaleUpAndDown != 1.)
cv::pyrDown(src, src, cv::Size(cvRound(src.cols*dScaleUpAndDown), cvRound(src.rows*dScaleUpAndDown)));
//用于显示
cv::Mat showMat;
cv::cvtColor(src, showMat, cv::COLOR_GRAY2BGR);
//图像尺寸
int X = src.cols, Y = src.rows;
//解码结果
std::vector<EyemBarCode> *tpResults = new std::vector<EyemBarCode>();
//测试用
cv::Mat srcPrev, binary;
//高斯滤波去噪
int ksize = cvRound((iBlockSize + 1)*dScaleUpAndDown) % 2 == 0 ? cvRound((iBlockSize + 1)*dScaleUpAndDown) + 1 : cvRound((iBlockSize + 1)*dScaleUpAndDown);
cv::GaussianBlur(src, srcPrev, cv::Size(ksize, ksize), 0.3);
//条码来说会比背景值小,二维码来说会比背景值大
//计算导数
cv::Mat dx, dy, mag;
cv::Sobel(srcPrev, dx, CV_32F, 1, 0);
cv::Sobel(srcPrev, dy, CV_32F, 0, 1);
//计算梯度幅值
cv::magnitude(dx, dy, mag);
// 归一化
cv::normalize(mag, mag, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(mag, srcPrev);
//二值化
cv::threshold(srcPrev, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//膨胀
cv::morphologyEx(binary, binary, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown / 3.), cvRound(iBlockSize*dScaleUpAndDown / 3.))));
//图像增强
//double min, max;
//cv::minMaxLoc(src, &min, &max, NULL, NULL, binary);
////条码测试用
//cv::Mat xDer, yDer;
//cv::normalize(dx, dx, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
//cv::convertScaleAbs(dx, xDer);
//cv::normalize(dy, dy, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
//cv::convertScaleAbs(dy, yDer);
cv::Mat mphyEx;
cv::morphologyEx(src, mphyEx, cv::MORPH_BLACKHAT, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown) * 2 + 1, cvRound(iBlockSize*dScaleUpAndDown) * 2 + 1)));
//确定背景
//cv::Mat binary4;
//cv::threshold(mphyEx, binary4, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//double min, max;
//cv::minMaxLoc(src, &min, &max, NULL, NULL, mphyEx);
//cv::Mat background(Y, X, CV_8UC1, max);
//src.copyTo(background, binary4);
cv::Mat edge;
cv::Canny(mphyEx, edge, 100, 200);
src = edge;
//计算角点响应
cv::Mat harMap;
cv::cornerHarris(src, harMap, cvRound(iBlockSize*dScaleUpAndDown), 3, 0.04);//对二维码效果比较好
// 归一化与转换
cv::normalize(harMap, harMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
cv::convertScaleAbs(harMap, harMap);
//计算背景像素
const int histSize = 256;
float range[] = { 0,255 };
const float* histRange = { range };
//calculate the histogram
cv::Mat hist;
cv::calcHist(&harMap, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
//calculate the background pixels
int maxIdx[2] = { 255,255 };
cv::minMaxIdx(hist, NULL, NULL, NULL, maxIdx);
//m1用于检测一维码;m2用于检测二维码
cv::Mat m1(Y, X, CV_8UC1, cv::Scalar(0)), m2(Y, X, CV_8UC1, cv::Scalar(0));
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 0; x < X; x++)
{
if (harMap.ptr<uint8_t>(y)[x] < maxIdx[0])
{
m1.ptr<uint8_t>(y)[x] = 255;
}
else if (harMap.ptr<uint8_t>(y)[x] > maxIdx[0])
{
m2.ptr<uint8_t>(y)[x] = 255;
}
}
}
});
//测试用
return FUNC_OK;
//确定识别类型
std::vector<std::string> hints_;
split(ccCodeType, "|", hints_);
//是否添加一维码检测
bool addOneDReader = std::find(hints_.begin(), hints_.end(), "UPC_A") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "UPC_E") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "EAN_8") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "EAN_13") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "CODABAR") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "CODE_39") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "CODE_93") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "CODE_128") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "ITF") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "RSS_14") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "RSS_EXPANDED") != hints_.end();
//是否添加二维码检测
bool addTwoDReader = std::find(hints_.begin(), hints_.end(), "QR_CODE") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "DATA_MATRIX") != hints_.end() ||
std::find(hints_.begin(), hints_.end(), "AZTEC") != hints_.end();
//未设置识别类型
if (!addOneDReader && !addTwoDReader)
return FUNC_CANNOT_CALC;
//所有解码内容
std::vector<DecodeResult> decodeResults;
//待解码区域,区分条码类型来识别
std::vector<WaitArea> waitAreas;
if (addOneDReader)
{
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(m1, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
if ((stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize*dScaleUpAndDown, 2) * 5) | (m1.ptr<uint8_t>(cvRound(centroids.ptr<double>(i)[1]))[cvRound(centroids.ptr<double>(i)[0])] == 0))
{
colors[i] = 0;
}
}
//过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = m1.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//用于过滤非条码部分
cv::Mat binFilter;
cv::adaptiveThreshold(backup, binFilter, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, ksize, 5);
//处理断裂一维码
cv::morphologyEx(m1, m1, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown), cvRound(iBlockSize*dScaleUpAndDown))));
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(m1, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//最大宽度限制
double minLen = cv::min(rect.size.height, rect.size.width);
if (minLen < 8.*iBlockSize*dScaleUpAndDown*(1. + dToleErr))
{
//增加比例过滤条件
cv::Point2f pts[4];
rect.points(pts);
//起点、终点、中点
cv::Point ptStart, ptEnd, ptMid;
if (cv::norm(pts[0] - pts[1]) > cv::norm(pts[1] - pts[2]))
{
ptStart = cv::Point((pts[0] + pts[3]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[1] + pts[2]) / 2. / dScaleUpAndDown);
}
else
{
ptStart = cv::Point((pts[0] + pts[1]) / 2. / dScaleUpAndDown); ptEnd = cv::Point((pts[2] + pts[3]) / 2. / dScaleUpAndDown);
}
ptMid = (ptStart + ptEnd) / 2;
cv::LineIterator it(binFilter, (ptMid + ptEnd) / 2, (ptMid + ptStart) / 2, 4);
double dis = cv::norm((ptMid + ptEnd) / 2 - (ptMid + ptStart) / 2);
uint8_t future_pixel = 255;
//扫描像素密度,比例接近1:1记录下来,并且黑白间隔数目小大于长度的一半
int flag = 0;
double test_line[2]{ 0 };
for (int n = 0; n < it.count; n++, ++it)
{
if (m1.ptr<uint8_t>(cvRound(it.pos().y * dScaleUpAndDown))[cvRound(it.pos().x * dScaleUpAndDown)] == 0) continue;
//统计均匀性
uint8_t next_pixel = binFilter.ptr<uint8_t>(it.pos().y)[it.pos().x];
test_line[next_pixel % 254]++;
if (next_pixel != future_pixel)
{
flag++;
future_pixel = 255 - future_pixel;
}
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
}
//满足比例
double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && flag > cvRound((dis / 4.)*(1. - dToleErr)))
{
cv::Point2f pt[4];
cv::Size size(cvRound(cv::max(rect.size.height, rect.size.width) + iBlockSize*dScaleUpAndDown / 4.), cvRound(cv::min(rect.size.height, rect.size.width)));
//获取roi位置
double _angle = std::atan2((ptEnd.y - ptStart.y), (ptEnd.x - ptStart.x));
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
pt[0].x = rect.center.x - a*size.height - b*size.width;
pt[0].y = rect.center.y + b*size.height - a*size.width;
pt[1].x = rect.center.x + a*size.height - b*size.width;
pt[1].y = rect.center.y - b*size.height - a*size.width;
pt[2].x = 2 * rect.center.x - pt[0].x;
pt[2].y = 2 * rect.center.y - pt[0].y;
pt[3].x = 2 * rect.center.x - pt[1].x;
pt[3].y = 2 * rect.center.y - pt[1].y;
//防止越界
for (int n = 0; n < 4; n++)
{
if (pt[n].x < 0) pt[n].x = 0.f; if (pt[n].x >= X - 1) pt[n].x = float(X - 1); if (pt[n].y < 0) pt[n].y = 0.f; if (pt[n].y >= Y - 1) pt[n].y = float(Y - 1);
}
//用采样的方式提取待解码区域
cv::LineIterator itStHeight(backup, pt[0], pt[1], 4);
cv::LineIterator itEdHeight(backup, pt[3], pt[2], 4);
cv::LineIterator itStWidth(backup, pt[0], pt[3], 4);
cv::LineIterator itEdWidth(backup, pt[1], pt[2], 4);
struct Track
{
cv::Point PosS;
cv::Point PosE;
Track() {};
Track(cv::Point PosS, cv::Point PosE) :PosS(PosS), PosE(PosE) {};
};
std::vector<Track> pairStEd(cv::min(itStHeight.count, itEdHeight.count));
for (int n = 0; n < pairStEd.size(); n++, ++itStHeight, ++itEdHeight)
{
pairStEd[n] = Track(itStHeight.pos(), itEdHeight.pos());
}
int iSamplingStep = int(pairStEd.size()) / 4;
//线采样
cv::Mat srcSampling(cv::Size(cv::max(itStWidth.count, itEdWidth.count), 1), CV_8UC1, cv::Scalar(255));
//
std::vector<cv::Mat> oneDMats;
//行
for (int n = 0; n < (int)pairStEd.size(); n += iSamplingStep)
{
cv::LineIterator it(backup, pairStEd[n].PosS, pairStEd[n].PosE, 4);
for (int nn = 0; nn < it.count; nn++, ++it)//列
{
//showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
srcSampling.ptr<uint8_t>(0)[nn] = backup.ptr<uint8_t>(it.pos().y)[it.pos().x];
}
//判断是否为二维码
cv::Mat testMat;
cv::threshold(srcSampling, testMat, 0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
//
cv::Mat testLabels;
if (cv::connectedComponents(testMat, testLabels) < 6)
{
//判断非二维码
break;
}
//扩展
cv::Mat waitArea;
cv::copyMakeBorder(srcSampling, waitArea, 0, 1, 60, 60, cv::BORDER_REPLICATE);
oneDMats.push_back(waitArea);
}
//存储一维码待解码区域
if ((int)oneDMats.size() > 0)
{
//画图
for (int j = 0; j < 4; j++)
{
cv::line(showMat, pt[j], pt[(j + 1) % 4], cv::Scalar(0, 255, 255), 1);
}
cv::circle(showMat, pt[0], 2, cv::Scalar(255, 0, 0), -1);
cv::circle(showMat, pt[1], 2, cv::Scalar(0, 255, 0), -1);
cv::circle(showMat, pt[2], 2, cv::Scalar(0, 0, 255), -1);
waitAreas.push_back(WaitArea(cv::Mat(), ptMid, getThreshVal_Otsu_8u(oneDMats[0]), _angle*180. / PI, true, oneDMats));
}
}
}
}
}
if (addTwoDReader)
{
//断裂处连接在一起
cv::morphologyEx(m2, m2, cv::MORPH_DILATE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(cvRound(iBlockSize*dScaleUpAndDown), cvRound(iBlockSize*dScaleUpAndDown))));
//去掉无关区域
cv::bitwise_and(binary, m2, m2);
//对二值图像过滤
cv::Mat labels, stats, centroids;
int nccomps = cv::connectedComponentsWithStats(m2, labels, stats, centroids, 4);
//过滤连通域面积及长/宽比例不符合的,允许50%误差
std::vector<uchar> colors(nccomps + 1, 0);
for (int i = 1; i < nccomps; i++) {
colors[i] = 255;
double dRate = (double)stats.ptr<int>(i)[cv::CC_STAT_WIDTH] / (double)stats.ptr<int>(i)[cv::CC_STAT_HEIGHT];
if ((!(dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))) | (stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize*dScaleUpAndDown * 15 * 1.414*(1. + dToleErr))\
| ((double)stats.ptr<int>(i)[cv::CC_STAT_AREA] < std::pow(iBlockSize / 2, 2) * 15))
{
colors[i] = 0;
}
}
//第一次过滤
cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
for (int y = range.start; y < range.end; y++)
{
uint8_t *ptrRow = m2.ptr<uint8_t>(y);
for (int x = 0; x < X; x++)
{
int label = labels.ptr<int>(y)[x];
CV_Assert(0 <= label && label <= nccomps);
ptrRow[x] = colors[label];
}
}
});
//用于轮廓检测
std::vector<std::vector<cv::Point>> contourAll, contourFilter;
findContours(m2, contourAll, cv::noArray(), cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
{
cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
//满足矩形条件与面积条件
double dRate = cv::min(rect.size.width, rect.size.height) / cv::max(rect.size.height, rect.size.width);
if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && ((double)rect.size.width > double(8. * iBlockSize*dScaleUpAndDown)) && ((double)rect.size.height > double(8. * iBlockSize*dScaleUpAndDown)))
{
contourFilter.push_back(contourAll[i]);
}
}
for (int i = 0; i < contourFilter.size(); i++)
{
cv::Rect rect = cv::minAreaRect(contourFilter[i]).boundingRect();
cv::RotatedRect rRect = cv::minAreaRect(contourFilter[i]);
//外包矩形
int dynSize = cvRound(cv::max((double)rect.size().height / dScaleUpAndDown, (double)rect.size().width / dScaleUpAndDown));
//疑似二维码区域
cv::Mat waitArea = backup(cv::Range(cv::max(0, cvRound(rRect.center.y / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(backup.rows - 1, cvRound(rRect.center.y / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2))), cv::Range(cv::max(0, cvRound(rRect.center.x / dScaleUpAndDown) - cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)), cv::min(backup.cols - 1, cvRound(rRect.center.x / dScaleUpAndDown) + cvRound(4.*(double)iBlockSize*dScaleUpAndDown + dynSize / 2)))).clone();
////获取起始阈值
//double threshVal = getThreshVal_Otsu_8u(waitArea);
////去掉背景
//cv::parallel_for_(cv::Range(0, waitArea.rows), [&](const cv::Range range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// for (int x = 0; x < waitArea.cols; x++)
// {
// if (waitArea.ptr<uint8_t>(y)[x] > threshVal + 7)
// {
// waitArea.ptr<uint8_t>(y)[x] = cvRound(threshVal);
// }
// }
// }
//});
////处理后再压入识别
//cv::Mat locHarMap;
//cv::cornerHarris(waitArea, locHarMap, cvRound(iBlockSize*dScaleUpAndDown), 3, 0.04);
//// 归一化与转换
//cv::normalize(locHarMap, locHarMap, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
//cv::convertScaleAbs(locHarMap, locHarMap);
////二值化
//cv::Mat binary;
//cv::threshold(locHarMap, binary, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//处理后再压入识别
waitAreas.push_back(WaitArea(waitArea, cv::Point(cvRound(rRect.center.x / dScaleUpAndDown), cvRound(rRect.center.y / dScaleUpAndDown)), 0, 0, false, std::vector<cv::Mat>()));
//画图
cv::rectangle(showMat, rect, cv::Scalar(0, 255, 0), 1);
}
////绘制图形
//for (int j = 0; j < contourFilter.size(); j++)
//{
// cv::Point2f pts[4];
// cv::minAreaRect(contourFilter[j]).points(pts);
// //画透明蒙版
// std::vector<cv::Point> vT = { cv::Point(pts[0]),cv::Point(pts[1]) ,cv::Point(pts[2]) ,cv::Point(pts[3]) };
// cv::fillConvexPoly(showMat, vT, cv::Scalar(0, 255, 255));
//}
}
//cv::Mat dst;
//showMat.copyTo(dst);
//解码
decodeMul(waitAreas, hints_, showMat, decodeResults, iBlockSize, iRangeC, dMinorStep);
//输出结果
for (int i = 0; i < decodeResults.size(); i++)
{
EyemBarCode tpResult;
tpResult.iCenterX = decodeResults[i].ptResult.x;
tpResult.iCenterY = decodeResults[i].ptResult.y;
tpResult.dAngle = decodeResults[i].dAngle;
//分配内容所需内存
tpResult.lpszText = (char *)CoTaskMemAlloc(512);
if (NULL != tpResult.lpszText)
{
char file[512] = { 0 };
sprintf_s(file, "%s", decodeResults[i].strResultText.c_str());
strcpy(tpResult.lpszText, file);
}
else return FUNC_NOT_ENOUGH_MEM;
//分配码型所需内存
tpResult.lpszType = (char *)CoTaskMemAlloc(512);
if (NULL != tpResult.lpszType)
{
char file[512] = { 0 };
sprintf_s(file, "%s", decodeResults[i].strResultType.c_str());
strcpy(tpResult.lpszType, file);
}
else return FUNC_NOT_ENOUGH_MEM;
//添加结果
tpResults->push_back(tpResult);
}
*hResults = tpResults->data();
*ipNum = static_cast<int>(tpResults->size());
*hObject = reinterpret_cast<IntPtr>(tpResults);
//cv::addWeighted(dst, 0.7, showMat, 0.3, 0, dst);
//showMat = dst;
//格式化文件名
const int bufSize = 32;
char file[bufSize * 4] = { 0 };
sprintf_s(file, "D:\\ResOut\\%s-Mark.png", ccFileName);
cv::imwrite(file, showMat);
return FUNC_OK;
////局部二值化
//cv::adaptiveThreshold(src, binary, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY_INV, iBlockSize, 2);
////去掉大部分干扰项
//binary &= mask;
////对二值图像过滤
//cv::Mat labels, stats, centroids;
//int nccomps = cv::connectedComponentsWithStats(binary, labels, stats, centroids, 4);
////过滤连通域面积及长/宽比例不符合的,允许50%误差
//std::vector<uchar> colors(nccomps + 1, 0);
//for (int i = 1; i < nccomps; i++) {
// colors[i] = 255;
// if ((stats.ptr<int>(i)[cv::CC_STAT_WIDTH] > iBlockSize * 15 * 1.414*(1. + dToleErr)) | (stats.ptr<int>(i)[cv::CC_STAT_HEIGHT] > iBlockSize * 15 * 1.414*(1. + dToleErr))\
// | (false))
// {
// colors[i] = 0;
// }
//}
////第一次过滤
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
////cv::cvtColor(binary, showMat, cv::COLOR_GRAY2BGR);
//const int iScanRadius = 35;
////最好还是用线扫描的方法,具体扫描全图还是按照中心点来扫看时间
////指定长度十字网格遍历是否满足条件黑白比例在1:1,考虑其他方式去扫描,可能速度上会慢一些,如果区分满足各自条件可能会好一些
////,这样可以将其他不必要的过滤掉,最后再合成一张图;2,扫描宽度,根据宽度流来确定是否属于条码、qr、datamatrix,黑白宽度;
////宽度打开都在一个很小变动范围内,允许50%的误差,宽度密度相较目前判断方式可也确定是否是黑白格分布,考虑到一维条码,八个方向只需满足一个方向即可
////这样可以过滤掉一些孤立长条
////vPts[0].Pt = cv::Point(3610, 2433);
//cv::Mat label(Y, X, CV_8UC1, cv::Scalar(0));
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// for (int x = 0; x < X; x++)
// {
// uint8_t future_pixel = binary.ptr<uint8_t>(y)[x];
// if (!future_pixel)
// {
// continue;
// }
// bool iFlag = 0;
// //判断白色像素部分占整条线的比例
// for (double t = -180; t < 180; t += 45)
// {
// float xx = float(x + iScanRadius * cos(t* 0.01745));
// float yy = float(y + iScanRadius * sin(t* 0.01745));
// //防止越界
// if (xx < 0) xx = 0; if (xx >= X - 1) xx = X - 1; if (yy < 0) yy = 0; if (yy >= Y - 1) yy = Y - 1;
// cv::LineIterator it(binary, cv::Point(x, y), cv::Point(cvRound(xx), cvRound(yy)), 4);
// //扫描像素密度,比例接近1:1记录下来
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 0 };
// for (int n = 0; n < it.count; n++, ++it)
// {
// //统计相邻由明到暗个数,并且查看均匀性
// uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (!next_pixel)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// }
// if (cv::max(test_line[0], test_line[1]) <= 0) continue;
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //showMat.at<cv::Vec3b>(cv::Point(x, y)) = cv::Vec3b(0, 255, 0);
// label.ptr<uint8_t>(y)[x] = 255;
// break;
// }
// }
// }
// }
//});
//for (int c = 0; c < (int)vPts.size(); c++)
//{
// bool iFlag = 0;
// uint8_t future_pixel = binary.ptr<uint8_t>(vPts[c].Pt.y)[vPts[c].Pt.x];
// //判断白色像素部分占整条线的比例
// for (double t = -180; t < 180; t += 45)
// {
// float x = float(vPts[c].Pt.x + iScanRadius * cos(t* 0.01745));
// float y = float(vPts[c].Pt.y + iScanRadius * sin(t* 0.01745));
// //防止越界
// if (x < 0) x = 0; if (x >= X - 1) x = X - 1; if (y < 0) y = 0; if (y >= Y - 1) y = Y - 1;
// cv::LineIterator it(binary, vPts[c].Pt, cv::Point(cvRound(x), cvRound(y)), 4);
// //扫描像素密度,比例接近1:1记录下来
// //测试用
// std::vector<cv::Point> test_point;
// int length = 0;
// std::vector<double> test_lines;
// double test_line[2]{ 0 };
// for (int n = 0; n < it.count; n++, ++it)
// {
// //统计相邻由明到暗个数,并且查看均匀性
// uint8_t next_pixel = binary.ptr<uint8_t>(it.pos().y)[it.pos().x];
// test_line[next_pixel % 254]++;
// length++;
// if (next_pixel != future_pixel)
// {
// if (length > 1)
// {
// test_lines.push_back(length);
// }
// future_pixel = 255 - future_pixel;
// length = 0;
// }
// //test_point.push_back(it.pos());
// //showMat.at<cv::Vec3b>(it.pos()) = cv::Vec3b(0, 255, 0);
// }
// //至少存在l个方向满足黑白1:1比例,并且满足黑白交替比例大概在1:1
// double dRate = cv::min(test_line[0], test_line[1]) / cv::max(test_line[0], test_line[1]);
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && (test_lines.size() >= T))
// {
// //满足条件,再判断当前方向的宽度是否
// iFlag = true;
// //cv::putText(showMat, "OK", vPts[c].Pt, cv::FONT_HERSHEY_PLAIN, 1, cv::Scalar(0, 0, 255));
// //for (int n = 0; n < test_point.size(); n++)
// //{
// // showMat.at<cv::Vec3b>(test_point[n]) = cv::Vec3b(0, 0, 255);
// //}
// //std::cout << "xx" << std::endl;
// }
// }
// //对四个方向进行进一步进行过滤,黑白间隔跨度阈值限定
// if ((!iFlag))
// {
// colors[vPts[c].Label] = 0;
// }
//}
//二次过滤
//cv::parallel_for_(cv::Range(0, Y), [&](const cv::Range& range)->void {
// for (int y = range.start; y < range.end; y++)
// {
// uint8_t *ptrRow = binary.ptr<uint8_t>(y);
// for (int x = 0; x < X; x++)
// {
// int label = labels.ptr<int>(y)[x];
// CV_Assert(0 <= label && label <= nccomps);
// ptrRow[x] = colors[label];
// }
// }
//});
//cv::Mat binPrev;
//cv::morphologyEx(label, binPrev, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(iBlockSize, iBlockSize)));
////用于轮廓检测(最终过滤过的图)
//std::vector<cv::Vec4i> hierarchy;
//std::vector<std::vector<cv::Point>> contourAll, contourFilter;
//findContours(binPrev, contourAll, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
//for (int i = 0; i < static_cast<int>(contourAll.size()); i++)
//{
// cv::RotatedRect rect = cv::minAreaRect(contourAll[i]);
// double dRate = rect.size.width / rect.size.height;
// std::vector<cv::Point> approx;
// cv::approxPolyDP(cv::Mat(contourAll[i]), approx, cv::arcLength(cv::Mat(contourAll[i]), true)*0.02, true);
// //满足四边形条件
// if (dRate >= (1. - dToleErr) && dRate <= (1. + dToleErr) && (approx.size() >= 4 && approx.size() < 8) && (cv::contourArea(contourAll[i]) > std::pow(iBlockSize * 12 * (1. - dToleErr), 2)))
// {
// contourFilter.push_back(contourAll[i]);
// }
//}
//if (contourFilter.size() < 1)
//{
// return FUNC_CANNOT_CALC;
//}
return FUNC_OK;
}
int eyemCalcDetectParameter(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, int *ipNum, int iBlockSize, const int iRangeC, int *iSymbolMin, int *iSymbolMax, double dScaleUpAndDown, double dMinorStep)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, tpImage.iDepth, tpImage.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
//提取ROI
src = src(cv::Rect(tpRoi.iXs, tpRoi.iYs, tpRoi.iWidth, tpRoi.iHeight));
//降采样
if (dScaleUpAndDown != 1.)
cv::pyrDown(src, src, cv::Size(cvRound(src.cols*dScaleUpAndDown), cvRound(src.rows*dScaleUpAndDown)));
//用于显示
cv::Mat showMat;
cv::cvtColor(src, showMat, cv::COLOR_GRAY2BGR);
//图像尺寸
int X = src.cols, Y = src.rows;
//高斯滤波去噪
cv::Mat srcPrev, binary;
int ksize = cvRound((iBlockSize + 1)*dScaleUpAndDown) % 2 == 0 ? cvRound((iBlockSize + 1)*dScaleUpAndDown) + 1 : cvRound((iBlockSize + 1)*dScaleUpAndDown);
cv::GaussianBlur(src, srcPrev, cv::Size(ksize, ksize), 0.3);
return FUNC_OK;
}
bool eyemDetectAndDecodeFree(IntPtr hObject)
{
std::vector<EyemBarCode> *tpResults = reinterpret_cast<std::vector<EyemBarCode>*>(hObject);
delete tpResults;
tpResults = NULL;
return true;
}
\ No newline at end of file
#pragma once
//
// eyemBarCode·标头
//
#ifndef __EYEM_BARCODE_H
#define __EYEM_BARCODE_H
#include "eyemLib.h"
#include "dmtx.h"
#include <zxing/common/Counted.h>
#include <zxing/Binarizer.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/Result.h>
#include <zxing/ReaderException.h>
#include <zxing/common/GlobalHistogramBinarizer.h>
#include <zxing/common/HybridBinarizer.h>
#include <zxing/Exception.h>
#include <zxing/common/IllegalArgumentException.h>
#include <zxing/BinaryBitmap.h>
#include <zxing/DecodeHints.h>
#include <zxing/qrcode/QRCodeReader.h>
#include <zxing/MultiFormatReader.h>
#include <zxing/MatSource.h>
#include <zxing\oned\MultiFormatOneDReader.h>
#include <zxing\datamatrix\DataMatrixReader.h>
#include <zxing\aztec\AztecReader.h>
#include <mutex>
#include <numeric>
#include <omp.h>
using namespace zxing;
using namespace zxing::qrcode;
std::mutex mtx;
enum {
NONE,
AZTEC,
CODABAR,
CODE_39,
CODE_93,
CODE_128,
DATA_MATRIX,
EAN_8,
EAN_13,
ITF,
MAXICODE,
PDF_417,
QR_CODE,
RSS_14,
RSS_EXPANDED,
UPC_A,
UPC_E,
UPC_EAN_EXTENSION
};
#define enumtoCharArr(val) #val
//
struct tMap
{
int Label;
cv::Point Pt;
tMap(int Label, cv::Point Pt) :Label(Label), Pt(Pt) {}
};
//预处理区域
struct WaitArea
{
double C;
double angle;
bool oneD = false;
std::vector<cv::Mat> oneDMats;
cv::Mat waitArea;
cv::Point Pt;
WaitArea(cv::Mat waitArea, cv::Point Pt, double C, double angle, bool oneD, std::vector<cv::Mat> oneDMats) :waitArea(waitArea), Pt(Pt), C(C), angle(angle), oneD(oneD), oneDMats(oneDMats) {}
};
//解码结果
struct DecodeResult
{
double dAngle;
cv::Point ptResult;
std::string strResultText;
std::string strResultType;
//构造函数
DecodeResult() {};
DecodeResult(double dAngle, cv::Point ptResult, std::string strResultText, std::string strResultType) :dAngle(dAngle), ptResult(ptResult), strResultText(strResultText), strResultType(strResultType) {}
//重载>运算符
bool operator >(const DecodeResult &te)const
{
return (*this).strResultText > te.strResultText;
}
//重载==运算符
bool operator ==(const DecodeResult &te)const
{
return strcmp((*this).strResultText.c_str(), te.strResultText.c_str()) == 0;
}
};
#endif/* __EYEM_BARCODE_H */
\ No newline at end of file
#include "eyemBin.h"
static int Huang(int hist[256])
{
// Implements Huang's fuzzy thresholding method
// Uses Shannon's entropy function (one can also use Yager's entropy function)
// Huang L.-K. and Wang M.-J.J. (1995) "Image Thresholding by Minimizing
// the Measures of Fuzziness" Pattern Recognition, 28(1): 41-51
// M. Emre Celebi 06.15.2007
// Ported to ImageJ plugin by G. Landini from E Celebi's fourier_0.8 routines
int threshold = -1;
int ih, it;
int first_bin;
int last_bin;
double sum_pix;
double num_pix;
double term;
double ent; // entropy
double min_ent; // min entropy
double mu_x;
/* Determine the first non-zero bin */
first_bin = 0;
for (ih = 0; ih < 256; ih++) {
if (hist[ih] != 0) {
first_bin = ih;
break;
}
}
/* Determine the last non-zero bin */
last_bin = 255;
for (ih = 255; ih >= first_bin; ih--) {
if (hist[ih] != 0) {
last_bin = ih;
break;
}
}
term = 1.0 / (double)(last_bin - first_bin);
double mu_0[256];
sum_pix = num_pix = 0;
for (ih = first_bin; ih < 256; ih++) {
sum_pix += (double)ih * hist[ih];
num_pix += hist[ih];
/* NUM_PIX cannot be zero ! */
mu_0[ih] = sum_pix / num_pix;
}
double mu_1[256];
sum_pix = num_pix = 0;
for (ih = last_bin; ih > 0; ih--) {
sum_pix += (double)ih * hist[ih];
num_pix += hist[ih];
/* NUM_PIX cannot be zero ! */
mu_1[ih - 1] = sum_pix / (double)num_pix;
}
/* Determine the threshold that minimizes the fuzzy entropy */
threshold = -1;
min_ent = DBL_MAX;
for (it = 0; it < 256; it++) {
ent = 0.0;
for (ih = 0; ih <= it; ih++) {
/* Equation (4) in Ref. 1 */
mu_x = 1.0 / (1.0 + term * abs(ih - mu_0[it]));
if (!((mu_x < 1e-06) || (mu_x > 0.999999))) {
/* Equation (6) & (8) in Ref. 1 */
ent += hist[ih] * (-mu_x * log(mu_x) - (1.0 - mu_x) * log(1.0 - mu_x));
}
}
for (ih = it + 1; ih < 256; ih++) {
/* Equation (4) in Ref. 1 */
mu_x = 1.0 / (1.0 + term * abs(ih - mu_1[it]));
if (!((mu_x < 1e-06) || (mu_x > 0.999999))) {
/* Equation (6) & (8) in Ref. 1 */
ent += hist[ih] * (-mu_x * log(mu_x) - (1.0 - mu_x) * log(1.0 - mu_x));
}
}
/* No need to divide by NUM_ROWS * NUM_COLS * LOG(2) ! */
if (ent < min_ent) {
min_ent = ent;
threshold = it;
}
}
return threshold;
}
static int IsoData(int hist[256])
{
// Also called intermeans
// Iterative procedure based on the isodata algorithm [T.W. Ridler, S. Calvard, Picture
// thresholding using an iterative selection method, IEEE Trans. System, Man and
// Cybernetics, SMC-8 (1978) 630-632.]
// The procedure divides the image into objects and background by taking an initial threshold,
// then the averages of the pixels at or below the threshold and pixels above are computed.
// The averages of those two values are computed, the threshold is incremented and the
// process is repeated until the threshold is larger than the composite average. That is,
// threshold = (average background + average objects)/2
// The code in ImageJ that implements this function is the getAutoThreshold() method in the ImageProcessor class.
//
// From: Tim Morris (dtm@ap.co.umist.ac.uk)
// Subject: Re: Thresholding method?
// posted to sci.image.processing on 1996/06/24
// The algorithm implemented in NIH Image sets the threshold as that grey
// value, G, for which the average of the averages of the grey values
// below and above G is equal to G. It does this by initialising G to the
// lowest sensible value and iterating:
// L = the average grey value of pixels with intensities < G
// H = the average grey value of pixels with intensities > G
// is G = (L + H)/2?
// yes => exit
// no => increment G and repeat
//
int i, l, totl, g = 0;
double toth, h;
for (i = 1; i < 256; i++) {
if (hist[i] > 0) {
g = i + 1;
break;
}
}
while (true) {
l = 0;
totl = 0;
for (i = 0; i < g; i++) {
totl = totl + hist[i];
l = l + (hist[i] * i);
}
h = 0;
toth = 0;
for (i = g + 1; i < 256; i++) {
toth += hist[i];
h += ((double)hist[i] * i);
}
if (totl > 0 && toth > 0) {
l /= totl;
h /= toth;
if (g == (int)round((l + h) / 2.0))
break;
}
g++;
if (g > 254)
return -1;
}
return g;
}
static int Li(int hist[256])
{
// Implements Li's Minimum Cross Entropy thresholding method
// This implementation is based on the iterative version (Ref. 2) of the algorithm.
// 1) Li C.H. and Lee C.K. (1993) "Minimum Cross Entropy Thresholding"
// Pattern Recognition, 26(4): 617-625
// 2) Li C.H. and Tam P.K.S. (1998) "An Iterative Algorithm for Minimum
// Cross Entropy Thresholding"Pattern Recognition Letters, 18(8): 771-776
// 3) Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
// Techniques and Quantitative Performance Evaluation" Journal of
// Electronic Imaging, 13(1): 146-165
// http://citeseer.ist.psu.edu/sezgin04survey.html
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold;
double num_pixels;
double sum_back; /* sum of the background pixels at a given threshold */
double sum_obj; /* sum of the object pixels at a given threshold */
double num_back; /* number of background pixels at a given threshold */
double num_obj; /* number of object pixels at a given threshold */
double old_thresh;
double new_thresh;
double mean_back; /* mean of the background pixels at a given threshold */
double mean_obj; /* mean of the object pixels at a given threshold */
double mean; /* mean gray-level in the image */
double tolerance; /* threshold tolerance */
double temp;
tolerance = 0.5;
num_pixels = 0;
for (int ih = 0; ih < 256; ih++)
num_pixels += hist[ih];
/* Calculate the mean gray-level */
mean = 0.0;
for (int ih = 0 + 1; ih < 256; ih++) //0 + 1?
mean += (double)ih * hist[ih];
mean /= num_pixels;
/* Initial estimate */
new_thresh = mean;
do {
old_thresh = new_thresh;
threshold = (int)(old_thresh + 0.5); /* range */
/* Calculate the means of background and object pixels */
/* Background */
sum_back = 0;
num_back = 0;
for (int ih = 0; ih <= threshold; ih++) {
sum_back += (double)ih * hist[ih];
num_back += hist[ih];
}
mean_back = (num_back == 0 ? 0.0 : (sum_back / (double)num_back));
/* Object */
sum_obj = 0;
num_obj = 0;
for (int ih = threshold + 1; ih < 256; ih++) {
sum_obj += (double)ih * hist[ih];
num_obj += hist[ih];
}
mean_obj = (num_obj == 0 ? 0.0 : (sum_obj / (double)num_obj));
/* Calculate the new threshold: Equation (7) in Ref. 2 */
//new_thresh = simple_round ( ( mean_back - mean_obj ) / ( Math.log ( mean_back ) - Math.log ( mean_obj ) ) );
//simple_round ( double x ) {
// return ( int ) ( IS_NEG ( x ) ? x - .5 : x + .5 );
//}
//
//#define IS_NEG( x ) ( ( x ) < -DBL_EPSILON )
//DBL_EPSILON = 2.220446049250313E-16
temp = (mean_back - mean_obj) / (log(mean_back) - log(mean_obj));
if (temp < -2.220446049250313E-16)
new_thresh = (int)(temp - 0.5);
else
new_thresh = (int)(temp + 0.5);
/* Stop the iterations when the difference between the
new and old threshold values is less than the tolerance */
} while (abs(new_thresh - old_thresh) > tolerance);
return threshold;
}
static int MaxEntropy(int hist[256])
{
// Implements Kapur-Sahoo-Wong (Maximum Entropy) thresholding method
// Kapur J.N., Sahoo P.K., and Wong A.K.C. (1985) "A New Method for
// Gray-Level Picture Thresholding Using the Entropy of the Histogram"
// Graphical Models and Image Processing, 29(3): 273-285
// M. Emre Celebi
// 06.15.2007
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold = -1;
int ih, it;
int first_bin;
int last_bin;
double tot_ent; /* total entropy */
double max_ent; /* max entropy */
double ent_back; /* entropy of the background pixels at a given threshold */
double ent_obj; /* entropy of the object pixels at a given threshold */
double norm_histo[256]; /* normalized histogram */
double P1[256]; /* cumulative normalized histogram */
double P2[256];
double total = 0;
for (ih = 0; ih < 256; ih++)
total += hist[ih];
for (ih = 0; ih < 256; ih++)
norm_histo[ih] = hist[ih] / total;
P1[0] = norm_histo[0];
P2[0] = 1.0 - P1[0];
for (ih = 1; ih < 256; ih++) {
P1[ih] = P1[ih - 1] + norm_histo[ih];
P2[ih] = 1.0 - P1[ih];
}
/* Determine the first non-zero bin */
first_bin = 0;
for (ih = 0; ih < 256; ih++) {
if (!(abs(P1[ih]) < 2.220446049250313E-16)) {
first_bin = ih;
break;
}
}
/* Determine the last non-zero bin */
last_bin = 255;
for (ih = 255; ih >= first_bin; ih--) {
if (!(abs(P2[ih]) < 2.220446049250313E-16)) {
last_bin = ih;
break;
}
}
// Calculate the total entropy each gray-level
// and find the threshold that maximizes it
max_ent = DBL_MIN;
for (it = first_bin; it <= last_bin; it++) {
/* Entropy of the background pixels */
ent_back = 0.0;
for (ih = 0; ih <= it; ih++) {
if (hist[ih] != 0) {
ent_back -= (norm_histo[ih] / P1[it]) * log(norm_histo[ih] / P1[it]);
}
}
/* Entropy of the object pixels */
ent_obj = 0.0;
for (ih = it + 1; ih < 256; ih++) {
if (hist[ih] != 0) {
ent_obj -= (norm_histo[ih] / P2[it]) * log(norm_histo[ih] / P2[it]);
}
}
/* Total entropy */
tot_ent = ent_back + ent_obj;
// IJ.log(""+max_ent+" "+tot_ent);
if (max_ent < tot_ent) {
max_ent = tot_ent;
threshold = it;
}
}
return threshold;
}
static int Mean(int hist[256])
{
// C. A. Glasbey, "An analysis of histogram-based thresholding algorithms,"
// CVGIP: Graphical Models and Image Processing, vol. 55, pp. 532-537, 1993.
//
// The threshold is the mean of the greyscale data
int threshold = -1;
double tot = 0, sum = 0;
for (int i = 0; i < 256; i++) {
tot += hist[i];
sum += ((double)i*hist[i]);
}
threshold = (int)floor(sum / tot);
return threshold;
}
static int Moments(int hist[256])
{
// W. Tsai, "Moment-preserving thresholding: a new approach," Computer Vision,
// Graphics, and Image Processing, vol. 29, pp. 377-393, 1985.
// Ported to ImageJ plugin by G.Landini from the the open source project FOURIER 0.8
// by M. Emre Celebi , Department of Computer Science, Louisiana State University in Shreveport
// Shreveport, LA 71115, USA
// http://sourceforge.net/projects/fourier-ipal
// http://www.lsus.edu/faculty/~ecelebi/fourier.htm
double total = 0;
double m0 = 1.0, m1 = 0.0, m2 = 0.0, m3 = 0.0, sum = 0.0, p0 = 0.0;
double cd, c0, c1, z0, z1; /* auxiliary variables */
int threshold = -1;
double histo[256];
for (int i = 0; i < 256; i++)
total += hist[i];
for (int i = 0; i < 256; i++)
histo[i] = (double)(hist[i] / total); //normalised histogram
/* Calculate the first, second, and third order moments */
for (int i = 0; i < 256; i++) {
double di = i;
m1 += di * histo[i];
m2 += di * di * histo[i];
m3 += di * di * di * histo[i];
}
/*
First 4 moments of the gray-level image should match the first 4 moments
of the target binary image. This leads to 4 equalities whose solutions
are given in the Appendix of Ref. 1
*/
cd = m0 * m2 - m1 * m1;
c0 = (-m2 * m2 + m1 * m3) / cd;
c1 = (m0 * -m3 + m2 * m1) / cd;
z0 = 0.5 * (-c1 - sqrt(c1 * c1 - 4.0 * c0));
z1 = 0.5 * (-c1 + sqrt(c1 * c1 - 4.0 * c0));
p0 = (z1 - m1) / (z1 - z0); /* Fraction of the object pixels in the target binary image */
// The threshold is the gray-level closest
// to the p0-tile of the normalized histogram
sum = 0;
for (int i = 0; i < 256; i++) {
sum += histo[i];
if (sum > p0) {
threshold = i;
break;
}
}
return threshold;
}
static int Otsu(int hist[])
{
// Otsu's threshold algorithm
// C++ code by Jordan Bevik <Jordan.Bevic@qtiworld.com>
// ported to ImageJ plugin by G.Landini
int k, kStar; // k = the current threshold; kStar = optimal threshold
double N1, N; // N1 = # points with intensity <=k; N = total number of points
double BCV, BCVmax; // The current Between Class Variance and maximum BCV
double num, denom; // temporary bookeeping
double Sk; // The total intensity for all histogram points <=k
double S, L = 256; // The total intensity of the image
// Initialize values:
S = N = 0;
for (k = 0; k < L; k++) {
S += (double)k * hist[k]; // Total histogram intensity
N += hist[k]; // Total number of data points
}
Sk = 0;
N1 = hist[0]; // The entry for zero intensity
BCV = 0;
BCVmax = 0;
kStar = 0;
// Look at each possible threshold value,
// calculate the between-class variance, and decide if it's a max
for (k = 1; k < L - 1; k++) { // No need to check endpoints k = 0 or k = L-1
Sk += (double)k * hist[k];
N1 += hist[k];
// The float casting here is to avoid compiler warning about loss of precision and
// will prevent overflow in the case of large saturated images
denom = (double)(N1) * (N - N1); // Maximum value of denom is (N^2)/4 = approx. 3E10
if (denom != 0) {
// Float here is to avoid loss of precision when dividing
num = ((double)N1 / N) * S - Sk; // Maximum value of num = 255*N = approx 8E7
BCV = (num * num) / denom;
}
else
BCV = 0;
if (BCV >= BCVmax) { // Assign the best threshold found so far
BCVmax = BCV;
kStar = k;
}
}
return kStar;
}
static double partialSum(int *y, int j)
{
double x = 0;
for (int i = 0; i <= j; i++)
x += y[i];
return x;
}
static int Percentile(int hist[])
{
// W. Doyle, "Operation useful for similarity-invariant pattern recognition,"
// Journal of the Association for Computing Machinery, vol. 9,pp. 259-267, 1962.
// ported to ImageJ plugin by G.Landini from Antti Niemisto's Matlab code (GPL)
// Original Matlab code Copyright (C) 2004 Antti Niemisto
// See http://www.cs.tut.fi/~ant/histthresh/ for an excellent slide presentation
// and the original Matlab code.
int iter = 0;
int threshold = -1;
double ptile = 0.5; // default fraction of foreground pixels
double avec[256];
for (int i = 0; i < 256; i++)
avec[i] = 0.0;
double total = partialSum(hist, 255);
double temp = 1.0;
for (int i = 0; i < 256; i++) {
avec[i] = abs((partialSum(hist, i) / total) - ptile);
if (avec[i] < temp) {
temp = avec[i];
threshold = i;
}
}
return threshold;
}
static int RenyiEntropy(int hist[])
{
// Kapur J.N., Sahoo P.K., and Wong A.K.C. (1985) "A New Method for
// Gray-Level Picture Thresholding Using the Entropy of the Histogram"
// Graphical Models and Image Processing, 29(3): 273-285
// M. Emre Celebi
// 06.15.2007
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold;
int opt_threshold;
int ih, it;
int first_bin;
int last_bin;
int tmp_var;
int t_star1, t_star2, t_star3;
int beta1, beta2, beta3;
double alpha;/* alpha parameter of the method */
double term;
double tot_ent; /* total entropy */
double max_ent; /* max entropy */
double ent_back; /* entropy of the background pixels at a given threshold */
double ent_obj; /* entropy of the object pixels at a given threshold */
double omega;
double norm_histo[256]; /* normalized histogram */
double P1[256]; /* cumulative normalized histogram */
double P2[256];
double total = 0;
for (ih = 0; ih < 256; ih++)
total += hist[ih];
for (ih = 0; ih < 256; ih++)
norm_histo[ih] = hist[ih] / total;
P1[0] = norm_histo[0];
P2[0] = 1.0 - P1[0];
for (ih = 1; ih < 256; ih++) {
P1[ih] = P1[ih - 1] + norm_histo[ih];
P2[ih] = 1.0 - P1[ih];
}
/* Determine the first non-zero bin */
first_bin = 0;
for (ih = 0; ih < 256; ih++) {
if (!(abs(P1[ih]) < 2.220446049250313E-16)) {
first_bin = ih;
break;
}
}
/* Determine the last non-zero bin */
last_bin = 255;
for (ih = 255; ih >= first_bin; ih--) {
if (!(abs(P2[ih]) < 2.220446049250313E-16)) {
last_bin = ih;
break;
}
}
/* Maximum Entropy Thresholding - BEGIN */
/* ALPHA = 1.0 */
/* Calculate the total entropy each gray-level
and find the threshold that maximizes it
*/
threshold = 0; // was MIN_INT in original code, but if an empty image is processed it gives an error later on.
max_ent = 0.0;
for (it = first_bin; it <= last_bin; it++) {
/* Entropy of the background pixels */
ent_back = 0.0;
for (ih = 0; ih <= it; ih++) {
if (hist[ih] != 0) {
ent_back -= (norm_histo[ih] / P1[it]) * log(norm_histo[ih] / P1[it]);
}
}
/* Entropy of the object pixels */
ent_obj = 0.0;
for (ih = it + 1; ih < 256; ih++) {
if (hist[ih] != 0) {
ent_obj -= (norm_histo[ih] / P2[it]) * log(norm_histo[ih] / P2[it]);
}
}
/* Total entropy */
tot_ent = ent_back + ent_obj;
if (max_ent < tot_ent) {
max_ent = tot_ent;
threshold = it;
}
}
t_star2 = threshold;
/* Maximum Entropy Thresholding - END */
threshold = 0; //was MIN_INT in original code, but if an empty image is processed it gives an error later on.
max_ent = 0.0;
alpha = 0.5;
term = 1.0 / (1.0 - alpha);
for (it = first_bin; it <= last_bin; it++) {
/* Entropy of the background pixels */
ent_back = 0.0;
for (ih = 0; ih <= it; ih++)
ent_back += sqrt(norm_histo[ih] / P1[it]);
/* Entropy of the object pixels */
ent_obj = 0.0;
for (ih = it + 1; ih < 256; ih++)
ent_obj += sqrt(norm_histo[ih] / P2[it]);
/* Total entropy */
tot_ent = term * ((ent_back * ent_obj) > 0.0 ? log(ent_back * ent_obj) : 0.0);
if (tot_ent > max_ent) {
max_ent = tot_ent;
threshold = it;
}
}
t_star1 = threshold;
threshold = 0; //was MIN_INT in original code, but if an empty image is processed it gives an error later on.
max_ent = 0.0;
alpha = 2.0;
term = 1.0 / (1.0 - alpha);
for (it = first_bin; it <= last_bin; it++) {
/* Entropy of the background pixels */
ent_back = 0.0;
for (ih = 0; ih <= it; ih++)
ent_back += (norm_histo[ih] * norm_histo[ih]) / (P1[it] * P1[it]);
/* Entropy of the object pixels */
ent_obj = 0.0;
for (ih = it + 1; ih < 256; ih++)
ent_obj += (norm_histo[ih] * norm_histo[ih]) / (P2[it] * P2[it]);
/* Total entropy */
tot_ent = term *((ent_back * ent_obj) > 0.0 ? log(ent_back * ent_obj) : 0.0);
if (tot_ent > max_ent) {
max_ent = tot_ent;
threshold = it;
}
}
t_star3 = threshold;
/* Sort t_star values */
if (t_star2 < t_star1) {
tmp_var = t_star1;
t_star1 = t_star2;
t_star2 = tmp_var;
}
if (t_star3 < t_star2) {
tmp_var = t_star2;
t_star2 = t_star3;
t_star3 = tmp_var;
}
if (t_star2 < t_star1) {
tmp_var = t_star1;
t_star1 = t_star2;
t_star2 = tmp_var;
}
/* Adjust beta values */
if (abs(t_star1 - t_star2) <= 5) {
if (abs(t_star2 - t_star3) <= 5) {
beta1 = 1;
beta2 = 2;
beta3 = 1;
}
else {
beta1 = 0;
beta2 = 1;
beta3 = 3;
}
}
else {
if (abs(t_star2 - t_star3) <= 5) {
beta1 = 3;
beta2 = 1;
beta3 = 0;
}
else {
beta1 = 1;
beta2 = 2;
beta3 = 1;
}
}
/* Determine the optimal threshold value */
omega = P1[t_star3] - P1[t_star1];
opt_threshold = (int)(t_star1 * (P1[t_star1] + 0.25 * omega * beta1) + 0.25 * t_star2 * omega * beta2 + t_star3 * (P2[t_star3] + 0.25 * omega * beta3));
return opt_threshold;
}
static int Shanbhag(int hist[])
{
// Shanhbag A.G. (1994) "Utilization of Information Measure as a Means of
// Image Thresholding" Graphical Models and Image Processing, 56(5): 414-419
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold;
int ih, it;
int first_bin;
int last_bin;
double term;
double tot_ent; /* total entropy */
double min_ent; /* max entropy */
double ent_back; /* entropy of the background pixels at a given threshold */
double ent_obj; /* entropy of the object pixels at a given threshold */
double norm_histo[256]; /* normalized histogram */
double P1[256]; /* cumulative normalized histogram */
double P2[256];
double total = 0;
for (ih = 0; ih < 256; ih++)
total += hist[ih];
for (ih = 0; ih < 256; ih++)
norm_histo[ih] = hist[ih] / total;
P1[0] = norm_histo[0];
P2[0] = 1.0 - P1[0];
for (ih = 1; ih < 256; ih++) {
P1[ih] = P1[ih - 1] + norm_histo[ih];
P2[ih] = 1.0 - P1[ih];
}
/* Determine the first non-zero bin */
first_bin = 0;
for (ih = 0; ih < 256; ih++) {
if (!(abs(P1[ih]) < 2.220446049250313E-16)) {
first_bin = ih;
break;
}
}
/* Determine the last non-zero bin */
last_bin = 255;
for (ih = 255; ih >= first_bin; ih--) {
if (!(abs(P2[ih]) < 2.220446049250313E-16)) {
last_bin = ih;
break;
}
}
// Calculate the total entropy each gray-level
// and find the threshold that maximizes it
threshold = -1;
min_ent = DBL_MAX;
for (it = first_bin; it <= last_bin; it++) {
/* Entropy of the background pixels */
ent_back = 0.0;
term = 0.5 / P1[it];
for (ih = 1; ih <= it; ih++) { //0+1?
ent_back -= norm_histo[ih] * log(1.0 - term * P1[ih - 1]);
}
ent_back *= term;
/* Entropy of the object pixels */
ent_obj = 0.0;
term = 0.5 / P2[it];
for (ih = it + 1; ih < 256; ih++) {
ent_obj -= norm_histo[ih] * log(1.0 - term * P2[ih]);
}
ent_obj *= term;
/* Total entropy */
tot_ent = abs(ent_back - ent_obj);
if (tot_ent < min_ent) {
min_ent = tot_ent;
threshold = it;
}
}
return threshold;
}
static int Triangle(int hist[]) {
// Zack, G. W., Rogers, W. E. and Latt, S. A., 1977,
// Automatic Measurement of Sister Chromatid Exchange Frequency,
// Journal of Histochemistry and Cytochemistry 25 (7), pp. 741-753
//
// modified from Johannes Schindelin plugin
//
// find min and max
int min = 0, dmax = 0, max = 0, min2 = 0;
for (int i = 0; i < 256; i++) {
if (hist[i] > 0) {
min = i;
break;
}
}
if (min > 0) min--; // line to the (p==0) point, not to data[min]
// The Triangle algorithm cannot tell whether the data is skewed to one side or another.
// This causes a problem as there are 2 possible thresholds between the max and the 2 extremes
// of the histogram.
// Here I propose to find out to which side of the max point the data is furthest, and use that as
// the other extreme.
for (int i = 255; i > 0; i--) {
if (hist[i] > 0) {
min2 = i;
break;
}
}
if (min2 < 255) min2++; // line to the (p==0) point, not to data[min]
for (int i = 0; i < 256; i++) {
if (hist[i] > dmax) {
max = i;
dmax = hist[i];
}
}
// find which is the furthest side
//IJ.log(""+min+" "+max+" "+min2);
bool inverted = false;
if ((max - min) < (min2 - max)) {
// reverse the histogram
inverted = true;
int left = 0; // index of leftmost element
int right = 255; // index of rightmost element
while (left < right) {
// exchange the left and right elements
int temp = hist[left];
hist[left] = hist[right];
hist[right] = temp;
// move the bounds toward the center
left++;
right--;
}
min = 255 - min2;
max = 255 - max;
}
if (min == max) {
return min;
}
// describe line by nx * x + ny * y - d = 0
double nx, ny, d;
// nx is just the max frequency as the other point has freq=0
nx = hist[max]; //-min; // data[min]; // lowest value bmin = (p=0)% in the image
ny = min - max;
d = sqrt(nx * nx + ny * ny);
nx /= d;
ny /= d;
d = nx * min + ny * hist[min];
// find split point
int split = min;
double splitDistance = 0;
for (int i = min + 1; i <= max; i++) {
double newDistance = nx * i + ny * hist[i] - d;
if (newDistance > splitDistance) {
split = i;
splitDistance = newDistance;
}
}
split--;
if (inverted) {
// The histogram might be used for something else, so let's reverse it back
int left = 0;
int right = 255;
while (left < right) {
int temp = hist[left];
hist[left] = hist[right];
hist[right] = temp;
left++;
right--;
}
return (255 - split);
}
else
return split;
}
static int Yen(int hist[])
{
// Implements Yen thresholding method
// 1) Yen J.C., Chang F.J., and Chang S. (1995) "A New Criterion
// for Automatic Multilevel Thresholding" IEEE Trans. on Image
// Processing, 4(3): 370-378
// 2) Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
// Techniques and Quantitative Performance Evaluation" Journal of
// Electronic Imaging, 13(1): 146-165
// http://citeseer.ist.psu.edu/sezgin04survey.html
//
// M. Emre Celebi
// 06.15.2007
// Ported to ImageJ plugin by G.Landini from E Celebi's fourier_0.8 routines
int threshold;
int ih, it;
double crit;
double max_crit;
double norm_histo[256]; /* normalized histogram */
double P1[256]; /* cumulative normalized histogram */
double P1_sq[256];
double P2_sq[256];
double total = 0;
for (ih = 0; ih < 256; ih++)
total += hist[ih];
for (ih = 0; ih < 256; ih++)
norm_histo[ih] = hist[ih] / total;
P1[0] = norm_histo[0];
for (ih = 1; ih < 256; ih++)
P1[ih] = P1[ih - 1] + norm_histo[ih];
P1_sq[0] = norm_histo[0] * norm_histo[0];
for (ih = 1; ih < 256; ih++)
P1_sq[ih] = P1_sq[ih - 1] + norm_histo[ih] * norm_histo[ih];
P2_sq[255] = 0.0;
for (ih = 254; ih >= 0; ih--)
P2_sq[ih] = P2_sq[ih + 1] + norm_histo[ih + 1] * norm_histo[ih + 1];
/* Find the threshold that maximizes the criterion */
threshold = -1;
max_crit = DBL_MIN;
for (it = 0; it < 256; it++) {
crit = -1.0 * ((P1_sq[it] * P2_sq[it]) > 0.0 ? log(P1_sq[it] * P2_sq[it]) : 0.0) + 2 * ((P1[it] * (1.0 - P1[it])) > 0.0 ? log(P1[it] * (1.0 - P1[it])) : 0.0);
if (crit > max_crit) {
max_crit = crit;
threshold = it;
}
}
return threshold;
}
static double
getThreshVal_Otsu_8u(const cv::Mat& _src)
{
cv::Size size = _src.size();
int step = (int)_src.step;
if (_src.isContinuous())
{
size.width *= size.height;
size.height = 1;
step = size.width;
}
#ifdef HAVE_IPP
unsigned char thresh = 0;
CV_IPP_RUN_FAST(ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
#endif
const int N = 256;
int i, j, h[N] = { 0 };
#if CV_ENABLE_UNROLLED
int h_unrolled[3][N] = {};
#endif
for (i = 0; i < size.height; i++)
{
const uchar* src = _src.ptr() + step*i;
j = 0;
#if CV_ENABLE_UNROLLED
for (; j <= size.width - 4; j += 4)
{
int v0 = src[j], v1 = src[j + 1];
h[v0]++; h_unrolled[0][v1]++;
v0 = src[j + 2]; v1 = src[j + 3];
h_unrolled[1][v0]++; h_unrolled[2][v1]++;
}
#endif
for (; j < size.width; j++)
h[src[j]]++;
}
double mu = 0, scale = 1. / (size.width*size.height);
for (i = 0; i < N; i++)
{
#if CV_ENABLE_UNROLLED
h[i] += h_unrolled[0][i] + h_unrolled[1][i] + h_unrolled[2][i];
#endif
mu += i*(double)h[i];
}
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for (i = 0; i < N; i++)
{
double p_i, q2, mu2, sigma;
p_i = h[i] * scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if (std::min(q1, q2) < FLT_EPSILON || std::max(q1, q2) > 1. - FLT_EPSILON)
continue;
mu1 = (mu1 + i*p_i) / q1;
mu2 = (mu - q1*mu1) / q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
if (sigma > max_sigma)
{
max_sigma = sigma;
max_val = i;
}
}
return max_val;
}
int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg)
{
std::cout << "Test 'eyemBinThreshold' " << std::endl;
cv::Mat image(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat binary;
//执行二值化操作
cv::threshold(image, binary, dThresh, dMaxVal, iLightDark);
return FUNC_OK;
}
int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinSize, double dK, int binMethod, double dR)
{
std::cout << "Test 'eyemBinSauvola' " << std::endl;
cv::Mat src(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
//CV_Assert(src.channels() == 1);
CV_Assert(iWinSize % 2 == 1 && iWinSize > 1);
if (binMethod == BINARIZATION_SAUVOLA) {
CV_Assert(src.depth() == CV_8U);
CV_Assert(dR != 0);
}
iType &= cv::THRESH_MASK;
cv::Mat thresh;
{
cv::Mat mean, sqmean, variance, stddev, sqrtVarianceMeanSum;
double srcMin, stddevMax;
boxFilter(src, mean, CV_32F, cv::Size(iWinSize, iWinSize),
cv::Point(-1, -1), true, cv::BORDER_REPLICATE);
sqrBoxFilter(src, sqmean, CV_32F, cv::Size(iWinSize, iWinSize),
cv::Point(-1, -1), true, cv::BORDER_REPLICATE);
variance = sqmean - mean.mul(mean);
sqrt(variance, stddev);
switch (binMethod)
{
case BINARIZATION_NIBLACK:
thresh = mean + stddev * static_cast<float>(dK);
break;
case BINARIZATION_SAUVOLA:
thresh = mean.mul(1. + static_cast<float>(dK) * (stddev / dR - 1.));
break;
case BINARIZATION_WOLF:
minMaxIdx(src, &srcMin);
minMaxIdx(stddev, NULL, &stddevMax);
thresh = mean - static_cast<float>(dK) * (mean - srcMin - stddev.mul(mean - srcMin) / stddevMax);
break;
case BINARIZATION_NICK:
sqrt(variance + sqmean, sqrtVarianceMeanSum);
thresh = mean + static_cast<float>(dK) * sqrtVarianceMeanSum;
break;
default:
break;
}
thresh.convertTo(thresh, src.depth());
}
cv::Mat dst(src.size(), CV_8U);
cv::Mat mask;
switch (iType)
{
case cv::THRESH_BINARY:
case cv::THRESH_BINARY_INV:
compare(src, thresh, mask, (iType == cv::THRESH_BINARY ? cv::CMP_GT : cv::CMP_LE));
dst.setTo(0);
dst.setTo(255, mask);
break;
case cv::THRESH_TRUNC:
compare(src, thresh, mask, cv::CMP_GT);
src.copyTo(dst);
thresh.copyTo(dst, mask);
break;
case cv::THRESH_TOZERO:
case cv::THRESH_TOZERO_INV:
compare(src, thresh, mask, (iType == cv::THRESH_TOZERO ? cv::CMP_GT : cv::CMP_LE));
dst.setTo(0);
src.copyTo(dst, mask);
break;
default:
break;
}
return FUNC_OK;
}
int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, EyemImage *tpDstImg)
{
std::cout << "Test 'eyemBinBinaryDynamic' " << std::endl;
cv::Mat src(tpSrcImg.iHeight, tpSrcImg.iWidth, CV_8UC1, tpSrcImg.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat srcMean, variance;
//cv::Mat srcMean = cv::Mat(tpThresholdImg.iHeight, tpThresholdImg.iWidth, CV_8UC1, tpThresholdImg.ucpImage);
//if (srcMean.empty()) {
// return FUNC_IMAGE_NOT_EXIST;
//}
cv::blur(src, srcMean, cv::Size(11, 7));
cv::Mat thresh;
{
switch (iLightDark)
{
case LIGHT:
variance = src - srcMean;
break;
case DARK:
variance = srcMean - src;
break;
case EQUAL:
variance = abs(src - srcMean);
break;
case NOT_EQUAL:
variance = abs(srcMean - src);
break;
default:
break;
}
}
cv::Mat binary, showMat;
cv::compare(variance, cv::Mat::ones(srcMean.size(), CV_8U)*iOffset, binary, cv::CMP_GT);
cv::add(src, cv::Mat::ones(src.size(), CV_8UC1) * 75, src);
cv::cvtColor(src.clone(), showMat, cv::COLOR_GRAY2BGR);
uchar * upBin = binary.data;
for (int y = 0; y < src.rows; y++)
{
for (int x = 0; x < src.cols; x++)
{
if (upBin[(x)+(y)*src.cols] != 0)
{
showMat.at<cv::Vec3b>(y, x) = cv::Vec3b(0, 255, 0);
}
}
}
cv::imwrite("smallpices.png", showMat);
//输出结果图
return FUNC_OK;
}
int eyemBinAutoThreshold(EyemImage tpImage, double dSigma, int iLightDark, int binMethod, EyemImage *tpDstImg)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
int(*calc_threshold_param) (int *) = 0;
int threshold = 0;
switch (binMethod)
{
case HUANG:
calc_threshold_param = Huang;
break;
case ISODATA:
calc_threshold_param = IsoData;
break;
case LI:
calc_threshold_param = Li;
break;
case MAXENTROPY:
calc_threshold_param = MaxEntropy;
break;
case MEAN:
calc_threshold_param = Mean;
break;
case MOMENTS:
calc_threshold_param = Moments;
break;
case OTSU:
calc_threshold_param = Otsu;
break;
default:
calc_threshold_param = Otsu;
break;
}
int hist[256];
std::memset(hist, 0, sizeof(hist));
//计算直方图
for (int Y = 0; Y < 256; Y++) hist[Y] = 0;
for (int Y = 0; Y < image.rows; Y++)
{
uchar *uPtr = image.data + Y * image.cols;
for (int X = 0; X < image.cols; X++, uPtr++) hist[*uPtr]++;
}
cv::Mat histMat = cv::Mat(1, 256, CV_32S, hist);
//对直方图滤波
cv::Mat F, G;
histMat.convertTo(F, CV_64F);
cv::Mat kernel = cv::getGaussianKernel(cvRound(dSigma * 3), dSigma);
cv::sepFilter2D(F, F, F.depth(), kernel, cv::Mat::ones(1, 1, CV_64F));
F.convertTo(G, CV_32S);
threshold = calc_threshold_param(hist);
cv::Mat binary;
cv::threshold(image, binary, threshold, 255, iLightDark | cv::THRESH_BINARY);
cv::Mat ker = cv::Mat::ones(3, 3, CV_8UC1);
cv::morphologyEx(binary, binary, cv::MORPH_OPEN, ker, cv::Point(-1, -1), 2);
cv::Mat bg;
cv::dilate(binary, bg, kernel, cv::Point(-1, -1), 3);
//# noise removal
// kernel = np.ones((3, 3), np.uint8)
// opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations = 2) # 形态开运算
// # sure background area
// sure_bg = cv2.dilate(opening, kernel, iterations = 3)
// # Finding sure foreground area
// dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
// ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)
// # Finding unknown region
// sure_fg = np.uint8(sure_fg)
// unknown = cv2.subtract(sure_bg, sure_fg)
cv::Mat distMap(image.size(), CV_32FC1);
cv::distanceTransform(binary, distMap, cv::noArray(), cv::DIST_L2, 5);
cv::normalize(distMap, distMap, 0, 255, cv::NORM_MINMAX);
distMap.convertTo(distMap, CV_8UC1);
cv::Mat fg;
cv::threshold(distMap, fg, 0.5 * 202, 255, 0);
fg.convertTo(fg, CV_8UC1);
cv::Mat unknown;
cv::subtract(bg, fg, unknown);
return FUNC_OK;
}
int eyemBinDilation(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg)
{
return FUNC_OK;
}
int eyemBinErosion(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg)
{
return FUNC_OK;
}
int eyemBinOpening(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg)
{
return FUNC_OK;
}
int eyemBinClosing(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg)
{
return FUNC_OK;
}
bool eyemBinFree(IntPtr hObject)
{
std::vector<EyemBinBlob> *tpResult = reinterpret_cast<std::vector<EyemBinBlob>*>(hObject);
delete tpResult;
tpResult = NULL;
return true;
}
#pragma once
//
// eyemBinͷ
//
#ifndef __EYEM_BIN_H
#define __EYEM_BIN_H
#include "eyemLib.h"
typedef unsigned int CvLabel;
const char cvChainCodeMoves[8][2] = {
{ 0, -1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
{ -1, 1 },
{ -1, 0 },
{ -1, -1 }
};
typedef unsigned char CvChainCode;
typedef std::list<CvChainCode> CvChainCodes;
typedef struct {
cv::Point startingPoint;
CvChainCodes chainCode;
} CvContourChainCode;
typedef std::list<CvContourChainCode *> CvContoursChainCode;
typedef struct {
CvLabel label; //ǩ
union
{
unsigned int area; //(moment 00)
unsigned int m00; //Moment 00
};
unsigned int minx; // X min.
unsigned int maxx; // X max.
unsigned int miny; // Y min.
unsigned int maxy; // Y max.
cv::Point2d centroid; //
double m10; ///< Moment 10.
double m01; ///< Moment 01.
double m11; ///< Moment 11.
double m20; ///< Moment 20.
double m02; ///< Moment 02.
double u11; ///< Central moment 11.
double u20; ///< Central moment 20.
double u02; ///< Central moment 02.
double n11; ///< Normalized central moment 11.
double n20; ///< Normalized central moment 20.
double n02; ///< Normalized central moment 02.
double p1; ///< Hu moment 1.
double p2; ///< Hu moment 2.
CvContourChainCode contour; ///< Contour.
CvContoursChainCode internalContours; ///< Internal contours.
} CvBlob;
typedef std::map<CvLabel, CvBlob *> CvBlobs;
typedef std::pair<CvLabel, CvBlob *> CvLabelBlob;
typedef std::map<CvLabel, cv::Scalar> Palete;
/// \def _HSV2RGB_(H, S, V, R, G, B)
/// \brief Color translation between HSV and RGB.
#define _HSV2RGB_(H, S, V, R, G, B) \
{ \
double _h = H/60.; \
int _hf = (int)floor(_h); \
int _hi = ((int)_h)%6; \
double _f = _h - _hf; \
\
double _p = V * (1. - S); \
double _q = V * (1. - _f * S); \
double _t = V * (1. - (1. - _f) * S); \
\
switch (_hi) \
{ \
case 0: \
R = 255.*V; G = 255.*_t; B = 255.*_p; \
break; \
case 1: \
R = 255.*_q; G = 255.*V; B = 255.*_p; \
break; \
case 2: \
R = 255.*_p; G = 255.*V; B = 255.*_t; \
break; \
case 3: \
R = 255.*_p; G = 255.*_q; B = 255.*V; \
break; \
case 4: \
R = 255.*_t; G = 255.*_p; B = 255.*V; \
break; \
case 5: \
R = 255.*V; G = 255.*_p; B = 255.*_q; \
break; \
} \
}
inline void cvReleaseBlobs(CvBlobs &blobs)
{
for (CvBlobs::iterator it = blobs.begin(); it != blobs.end(); ++it)
{
CvBlob *blob = (*it).second;
if (blob)
{
for (CvContoursChainCode::iterator jt = blob->internalContours.begin(); jt != blob->internalContours.end(); ++jt)
{
CvContourChainCode *contour = *jt;
if (contour)
delete contour;
}
blob->internalContours.clear();
delete blob;
}
}
blobs.clear();
}
#endif/* __EYEM_BIN_H */
\ No newline at end of file
#include "eyemCalib.h"
#pragma once
//
// eyemCalibͷ
//
#ifndef __EYEM_CALIB_H
#define __EYEM_CALIB_H
#include "eyemLib.h"
#endif/* __EYEM_CALIB_H */
#include "eyemLib.h"
void eyemClp2dDistanceTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, double &tpDist)
{
tpDist = std::sqrt(std::pow(tpPoint2.dX - tpPoint1.dX, 2) + std::pow(tpPoint2.dY - tpPoint1.dY, 2));
}
void eyemClp2dCenterTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY &tpCenter)
{
tpCenter.dX = (tpPoint1.dX + tpPoint2.dX) / 2.0;
tpCenter.dY = (tpPoint1.dY + tpPoint2.dY) / 2.0;
}
int eyemClp2dLineTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine)
{
if ((tpPoint1.dX - tpPoint2.dX) < DBL_EPS && (tpPoint1.dY - tpPoint2.dY) < DBL_EPS)
{
return FUNC_CANNOT_CALC;
}
tpLine.dA = -(tpPoint1.dY - tpPoint2.dY);
tpLine.dB = (tpPoint1.dX - tpPoint2.dX);
tpLine.dC = tpPoint2.dX*tpPoint1.dY - tpPoint1.dX*tpPoint2.dY;
return FUNC_OK;
}
int eyemClp2dMidperpendicularTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine)
{
if ((tpPoint1.dX - tpPoint2.dX) < DBL_EPS && (tpPoint1.dY - tpPoint2.dY) < DBL_EPS)
{
return FUNC_CANNOT_CALC;
}
tpLine.dA = 2 * (tpPoint2.dX - tpPoint1.dX);
tpLine.dB = 2 * (tpPoint2.dY - tpPoint1.dY);
tpLine.dC = pow(tpPoint1.dX, 2) - pow(tpPoint2.dX, 2) + pow(tpPoint1.dY, 2) - pow(tpPoint2.dY, 2);
return FUNC_OK;
}
int eyemClp2dVerticalLinePointAndLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, EyemOcsDABC &tpVertical)
{
double v = std::sqrt(std::pow(tpLine.dB, 2) + std::pow(-tpLine.dA, 2));
if (v < DBL_EPS)
{
return FUNC_CANNOT_CALC;
}
tpVertical.dA = tpLine.dB / v;
tpVertical.dB = -tpLine.dA / v;
tpVertical.dC = -tpVertical.dA*tpPoint.dX - tpVertical.dB*tpPoint.dY;
return FUNC_OK;
}
void eyemClp2dLinePointAndSlope(EyemOcsDXY tpPoint, double dSlope, EyemOcsDABC &tpLine)
{
//単位:rad
tpLine.dA = -sin(dSlope);
tpLine.dB = cos(dSlope);
tpLine.dC = -tpLine.dA*tpPoint.dX - tpLine.dB*tpPoint.dY;
}
int eyemClp2dIntersectionTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDXY &tpPoint)
{
if (abs(tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB) < DBL_EPS)
{
return FUNC_CANNOT_CALC;
}
//计算系数
double sa[4], sb[2], sx[2];
cv::Mat a = cv::Mat(2, 2, CV_64F, sa), b = cv::Mat(2, 1, CV_64F, sb);
//系数矩阵A*X=B;
cv::Mat x = cv::Mat(2, 1, CV_64F, sx);
std::memset(sa, 0, sizeof(sa));
std::memset(sb, 0, sizeof(sb));
std::memset(sx, 0, sizeof(sx));
sa[0] = tpLine1.dA, sa[1] = tpLine1.dB;
sa[2] = tpLine2.dA, sa[3] = tpLine2.dB;
sb[0] = -tpLine1.dC, sb[1] = -tpLine2.dC;
//solve
cv::solve(a, b, x, cv::DECOMP_SVD);
tpPoint.dX = sx[0];
tpPoint.dY = sx[1];
return FUNC_OK;
}
int eyemClp2dAngleTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, double &dpAngle)
{
double det = tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB;
if (abs(det) < DBL_EPS)
{
return FUNC_CANNOT_CALC;
}
double u, v, uv;
u = sqrt(pow(tpLine1.dA, 2) + pow(tpLine1.dB, 2));
v = sqrt(pow(tpLine2.dA, 2) + pow(tpLine2.dB, 2));
uv = sqrt(pow(tpLine1.dA*tpLine2.dB - tpLine2.dA*tpLine1.dB, 2));
dpAngle = asin(uv / u*v);
return FUNC_OK;
}
int eyemClp2dCenterLineOfTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDABC &tpLineC)
{
double la, lb, lc;
la = tpLine1.dA / (sqrt(pow(tpLine1.dA, 2) + pow(tpLine1.dB, 2))) + tpLine2.dA / (sqrt(pow(tpLine2.dA, 2) + pow(tpLine2.dB, 2)));
lb = tpLine1.dB / (sqrt(pow(tpLine1.dA, 2) + pow(tpLine1.dB, 2))) + tpLine2.dB / (sqrt(pow(tpLine2.dA, 2) + pow(tpLine2.dB, 2)));
lc = tpLine1.dC / (sqrt(pow(tpLine1.dA, 2) + pow(tpLine1.dB, 2))) + tpLine2.dC / (sqrt(pow(tpLine2.dA, 2) + pow(tpLine2.dB, 2)));
tpLineC.dA = la / (sqrt(pow(la, 2) + pow(lb, 2)));
tpLineC.dB = lb / (sqrt(pow(la, 2) + pow(lb, 2)));
tpLineC.dC = lc / (sqrt(pow(la, 2) + pow(lb, 2)));
return FUNC_OK;
}
int eyemClp2dDistancePointToLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, double &dpDist)
{
dpDist = abs(tpLine.dA*tpPoint.dX + tpLine.dB*tpPoint.dY + tpLine.dC) / sqrt(tpLine.dA*tpLine.dA + tpLine.dB*tpLine.dB);
return FUNC_OK;
}
int eyemClp2dTranslationOfLine(EyemOcsDABC tpSrcL, EyemOcsDXY tpTrans, EyemOcsDABC &tpDstL)
{
tpDstL.dA = tpSrcL.dA, tpDstL.dB = tpSrcL.dB;
tpDstL.dC = tpSrcL.dC - tpSrcL.dA*tpTrans.dX - tpSrcL.dB*tpTrans.dY;
return FUNC_OK;
}
void eyemClp2dAreaTriangle(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, double &dpArea)
{
dpArea = ((tpPoint2.dX - tpPoint1.dX)*(tpPoint3.dY - tpPoint1.dY) - ((tpPoint2.dY - tpPoint1.dY)*(tpPoint3.dX - tpPoint1.dX))) / 2.0;
}
int eyemClp2dCircleThreePoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, EyemOcsDXYR &tpCircle)
{
//计算系数
double sa[9], sb[3];
cv::Mat a = cv::Mat(3, 3, CV_64F, sa), b = cv::Mat(3, 1, CV_64F, sb);
//系数矩阵A*X=B;
cv::Mat x = cv::Mat(3, 1, CV_64F);
std::memset(sa, 0, sizeof(sa));
std::memset(sb, 0, sizeof(sb));
sa[0] = -2.0*tpPoint1.dX, sa[1] = -2.0*tpPoint1.dY, sa[2] = 1.;
sa[3] = -2.0*tpPoint2.dX, sa[4] = -2.0*tpPoint2.dY, sa[5] = 1.;
sa[6] = -2.0*tpPoint3.dX, sa[7] = -2.0*tpPoint3.dY, sa[8] = 1.;
sb[0] = -(pow(tpPoint1.dX, 2) + pow(tpPoint1.dY, 2)),
sb[1] = -(pow(tpPoint2.dX, 2) + pow(tpPoint2.dY, 2)),
sb[2] = -(pow(tpPoint3.dX, 2) + pow(tpPoint3.dY, 2));
//solve
cv::solve(a, b, x, cv::DECOMP_SVD);
tpCircle.dX = *x.ptr<double>(0);
tpCircle.dY = *x.ptr<double>(1);
tpCircle.dR = sqrt(pow(*x.ptr<double>(0), 2) + pow(*x.ptr<double>(1), 2) - (*x.ptr<double>(2)));
return FUNC_OK;
}
#pragma once
//
// eyemClp2dͷ
//
#ifndef __EYEM_CLP2D_H
#define __EYEM_CLP2D_H
#include "eyemLib.h"
#endif/* __EYEM_CLP2D_H */
文件属性发生变化
#include "eyemEDLinesDetector.h"
void detectE(cv::InputArray _image, cv::OutputArray _lines)
{
cv::Mat image = _image.getMat();
CV_Assert(!image.empty() && image.type() == CV_8UC1);
std::vector<cv::Vec4f> lines;
std::vector<SEGMENT> segments;
lineDetectionE(image, segments);
for (size_t i = 0; i < segments.size(); ++i)
{
const SEGMENT seg = segments[i];
cv::Vec4f line(seg.x1, seg.y1, seg.x2, seg.y2);
lines.push_back(line);
}
cv::Mat(lines).copyTo(_lines);
}
void drawSegmentsE(cv::InputOutputArray _image, cv::InputArray lines, bool draw_arrow)
{
CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3));
Mat gray;
if (_image.channels() == 1)
{
gray = _image.getMatRef();
}
else if (_image.channels() == 3)
{
cvtColor(_image, gray, COLOR_BGR2GRAY);
}
// Create a 3 channel image in order to draw colored lines
std::vector<Mat> planes;
planes.push_back(gray);
planes.push_back(gray);
planes.push_back(gray);
merge(planes, _image);
double gap = 10.0;
double arrow_angle = 30.0;
Mat _lines;
_lines = lines.getMat();
int N = _lines.checkVector(4);
// Draw segments
for (int i = 0; i < N; ++i)
{
const Vec4f& v = _lines.at<Vec4f>(i);
Point2f b(v[0], v[1]);
Point2f e(v[2], v[3]);
line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1);
if (draw_arrow)
{
SEGMENT seg;
seg.x1 = b.x;
seg.y1 = b.y;
seg.x2 = e.x;
seg.y2 = e.y;
getAngleE(seg);
double ang = (double)seg.angle;
Point2i p1;
p1.x = cvRound(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang));
p1.y = cvRound(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang));
pointInboardTestE(_image.getMatRef(), p1);
line(_image.getMatRef(), Point(cvRound(seg.x2), cvRound(seg.y2)), p1, Scalar(0, 0, 255), 1);
}
}
}
void mergeLinesE(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged)
{
double xg = 0.0, yg = 0.0;
double delta1x = 0.0, delta1y = 0.0, delta2x = 0.0, delta2y = 0.0;
float ax = 0, bx = 0, cx = 0, dx = 0;
float ay = 0, by = 0, cy = 0, dy = 0;
double li = 0.0, lj = 0.0;
double thi = 0.0, thj = 0.0, thr = 0.0;
double axg = 0.0, bxg = 0.0, cxg = 0.0, dxg = 0.0, delta1xg = 0.0, delta2xg = 0.0;
ax = seg1.x1;
ay = seg1.y1;
bx = seg1.x2;
by = seg1.y2;
cx = seg2.x1;
cy = seg2.y1;
dx = seg2.x2;
dy = seg2.y2;
float dlix = (bx - ax);
float dliy = (by - ay);
float dljx = (dx - cx);
float dljy = (dy - cy);
li = sqrt((double)(dlix * dlix) + (double)(dliy * dliy));
lj = sqrt((double)(dljx * dljx) + (double)(dljy * dljy));
xg = (li * (double)(ax + bx) + lj * (double)(cx + dx))
/ (double)(2.0 * (li + lj));
yg = (li * (double)(ay + by) + lj * (double)(cy + dy))
/ (double)(2.0 * (li + lj));
if (dlix == 0.0f) thi = CV_PI / 2.0;
else thi = atan(dliy / dlix);
if (dljx == 0.0f) thj = CV_PI / 2.0;
else thj = atan(dljy / dljx);
if (fabs(thi - thj) <= CV_PI / 2.0)
{
thr = (li * thi + lj * thj) / (li + lj);
}
else
{
double tmp = thj - CV_PI * (thj / fabs(thj));
thr = li * thi + lj * tmp;
thr /= (li + lj);
}
axg = ((double)ay - yg) * sin(thr) + ((double)ax - xg) * cos(thr);
bxg = ((double)by - yg) * sin(thr) + ((double)bx - xg) * cos(thr);
cxg = ((double)cy - yg) * sin(thr) + ((double)cx - xg) * cos(thr);
dxg = ((double)dy - yg) * sin(thr) + ((double)dx - xg) * cos(thr);
delta1xg = min(axg, min(bxg, min(cxg, dxg)));
delta2xg = max(axg, max(bxg, max(cxg, dxg)));
delta1x = delta1xg * cos(thr) + xg;
delta1y = delta1xg * sin(thr) + yg;
delta2x = delta2xg * cos(thr) + xg;
delta2y = delta2xg * sin(thr) + yg;
seg_merged.x1 = (float)delta1x;
seg_merged.y1 = (float)delta1y;
seg_merged.x2 = (float)delta2x;
seg_merged.y2 = (float)delta2y;
}
double distPointLineE(const Mat& p, Mat& l)
{
double x = l.at<double>(0, 0);
double y = l.at<double>(1, 0);
double w = sqrt(x*x + y*y);
l.at<double>(0, 0) = x / w;
l.at<double>(1, 0) = y / w;
l.at<double>(2, 0) = l.at<double>(2, 0) / w;
return l.dot(p);
}
bool mergeSegmentsE(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged)
{
double o[] = { 0.0, 0.0, 1.0 };
double a[] = { 0.0, 0.0, 1.0 };
double b[] = { 0.0, 0.0, 1.0 };
double c[3];
o[0] = (seg2.x1 + seg2.x2) / 2.0;
o[1] = (seg2.y1 + seg2.y2) / 2.0;
a[0] = seg1.x1;
a[1] = seg1.y1;
b[0] = seg1.x2;
b[1] = seg1.y2;
Mat ori = Mat(3, 1, CV_64FC1, o).clone();
Mat p1 = Mat(3, 1, CV_64FC1, a).clone();
Mat p2 = Mat(3, 1, CV_64FC1, b).clone();
Mat l1 = Mat(3, 1, CV_64FC1, c).clone();
l1 = p1.cross(p2);
Point2f seg1mid, seg2mid;
seg1mid.x = (seg1.x1 + seg1.x2) / 2.0f;
seg1mid.y = (seg1.y1 + seg1.y2) / 2.0f;
seg2mid.x = (seg2.x1 + seg2.x2) / 2.0f;
seg2mid.y = (seg2.y1 + seg2.y2) / 2.0f;
float seg1len = sqrt((seg1.x1 - seg1.x2)*(seg1.x1 - seg1.x2) + (seg1.y1 - seg1.y2)*(seg1.y1 - seg1.y2));
float seg2len = sqrt((seg2.x1 - seg2.x2)*(seg2.x1 - seg2.x2) + (seg2.y1 - seg2.y2)*(seg2.y1 - seg2.y2));
float middist = sqrt((seg1mid.x - seg2mid.x)*(seg1mid.x - seg2mid.x) + (seg1mid.y - seg2mid.y)*(seg1mid.y - seg2mid.y));
float angdiff = fabs(seg1.angle - seg2.angle);
float dist = (float)distPointLineE(ori, l1);
if (fabs(dist) <= threshold_dist * 2.0f && middist <= seg1len / 2.0f + seg2len / 2.0f + 20.0f
&& angdiff <= CV_PI / 180.0f * 5.0f)
{
mergeLinesE(seg1, seg2, seg_merged);
return true;
}
else
{
return false;
}
}
template<class T>
void incidentPointE(const Mat& l, T& pt)
{
double a[] = { (double)pt.x, (double)pt.y, 1.0 };
double b[] = { l.at<double>(0,0), l.at<double>(1,0), 0.0 };
double c[3];
Mat xk = Mat(3, 1, CV_64FC1, a).clone();
Mat lh = Mat(3, 1, CV_64FC1, b).clone();
Mat lk = Mat(3, 1, CV_64FC1, c).clone();
lk = xk.cross(lh);
xk = lk.cross(l);
xk.convertTo(xk, -1, 1.0 / xk.at<double>(2, 0));
Point2f pt_tmp;
pt_tmp.x = (float)xk.at<double>(0, 0) < 0.0f ? 0.0f : (float)xk.at<double>(0, 0)
>= (imagewidth - 1.0f) ? (imagewidth - 1.0f) : (float)xk.at<double>(0, 0);
pt_tmp.y = (float)xk.at<double>(1, 0) < 0.0f ? 0.0f : (float)xk.at<double>(1, 0)
>= (imageheight - 1.0f) ? (imageheight - 1.0f) : (float)xk.at<double>(1, 0);
pt = T(pt_tmp);
}
void extractSegmentsE(const std::vector<Point2i>& points, std::vector<SEGMENT>& segments)
{
bool is_line;
int i, j;
SEGMENT seg;
Point2i ps, pe, pt;
std::vector<Point2i> l_points;
int total = (int)points.size();
for (i = 0; i + threshold_length < total; i++)
{
ps = points[i];
pe = points[i + threshold_length];
double a[] = { (double)ps.x, (double)ps.y, 1 };
double b[] = { (double)pe.x, (double)pe.y, 1 };
double c[3], d[3];
Mat p1 = Mat(3, 1, CV_64FC1, a).clone();
Mat p2 = Mat(3, 1, CV_64FC1, b).clone();
Mat p = Mat(3, 1, CV_64FC1, c).clone();
Mat l = Mat(3, 1, CV_64FC1, d).clone();
l = p1.cross(p2);
is_line = true;
l_points.clear();
l_points.push_back(ps);
for (j = 1; j < threshold_length; j++)
{
pt.x = points[i + j].x;
pt.y = points[i + j].y;
p.at<double>(0, 0) = (double)pt.x;
p.at<double>(1, 0) = (double)pt.y;
p.at<double>(2, 0) = 1.0;
double dist = distPointLineE(p, l);
if (fabs(dist) > threshold_dist)
{
is_line = false;
break;
}
l_points.push_back(pt);
}
// Line check fail, test next point
if (is_line == false)
continue;
l_points.push_back(pe);
Vec4f line;
fitLine(Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
a[0] = line[2];
a[1] = line[3];
b[0] = line[2] + line[0];
b[1] = line[3] + line[1];
p1 = Mat(3, 1, CV_64FC1, a).clone();
p2 = Mat(3, 1, CV_64FC1, b).clone();
l = p1.cross(p2);
incidentPointE(l, ps);
// Extending line
for (j = threshold_length + 1; i + j < total; j++)
{
pt.x = points[i + j].x;
pt.y = points[i + j].y;
p.at<double>(0, 0) = (double)pt.x;
p.at<double>(1, 0) = (double)pt.y;
p.at<double>(2, 0) = 1.0;
double dist = distPointLineE(p, l);
if (fabs(dist) > threshold_dist)
{
fitLine(Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
a[0] = line[2];
a[1] = line[3];
b[0] = line[2] + line[0];
b[1] = line[3] + line[1];
p1 = Mat(3, 1, CV_64FC1, a).clone();
p2 = Mat(3, 1, CV_64FC1, b).clone();
l = p1.cross(p2);
dist = distPointLineE(p, l);
if (fabs(dist) > threshold_dist) {
j--;
break;
}
}
pe = pt;
l_points.push_back(pt);
}
fitLine(Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
a[0] = line[2];
a[1] = line[3];
b[0] = line[2] + line[0];
b[1] = line[3] + line[1];
p1 = Mat(3, 1, CV_64FC1, a).clone();
p2 = Mat(3, 1, CV_64FC1, b).clone();
l = p1.cross(p2);
Point2f e1, e2;
e1.x = (float)ps.x;
e1.y = (float)ps.y;
e2.x = (float)pe.x;
e2.y = (float)pe.y;
incidentPointE(l, e1);
incidentPointE(l, e2);
seg.x1 = e1.x;
seg.y1 = e1.y;
seg.x2 = e2.x;
seg.y2 = e2.y;
segments.push_back(seg);
i = i + j;
}
}
void pointInboardTestE(const Mat& src, Point2i& pt)
{
pt.x = pt.x <= 5 ? 5 : pt.x >= src.cols - 5 ? src.cols - 5 : pt.x;
pt.y = pt.y <= 5 ? 5 : pt.y >= src.rows - 5 ? src.rows - 5 : pt.y;
}
bool getPointChainE(const Mat& img, Point pt,
Point& chained_pt, float& direction, int step)
{
int ri, ci;
int indices[8][2] = { { 1,1 },{ 1,0 },{ 1,-1 },{ 0,-1 },
{ -1,-1 },{ -1,0 },{ -1,1 },{ 0,1 } };
float min_dir_diff = 7.0f;
Point consistent_pt;
int consistent_direction = 0;
for (int i = 0; i < 8; i++)
{
ci = pt.x + indices[i][1];
ri = pt.y + indices[i][0];
if (ri < 0 || ri == img.rows || ci < 0 || ci == img.cols)
continue;
if (img.at<unsigned char>(ri, ci) == 0)
continue;
if (step == 0)
{
chained_pt.x = ci;
chained_pt.y = ri;
// direction = (float)i;
direction = i > 4 ? (float)(i - 8) : (float)i;
return true;
}
else
{
float curr_dir = i > 4 ? (float)(i - 8) : (float)i;
float dir_diff = abs(curr_dir - direction);
dir_diff = dir_diff > 4.0f ? 8.0f - dir_diff : dir_diff;
if (dir_diff <= min_dir_diff)
{
min_dir_diff = dir_diff;
consistent_pt.x = ci;
consistent_pt.y = ri;
consistent_direction = i > 4 ? i - 8 : i;
}
}
}
if (min_dir_diff < 2.0f)
{
chained_pt.x = consistent_pt.x;
chained_pt.y = consistent_pt.y;
direction = (direction * (float)step + (float)consistent_direction)
/ (float)(step + 1);
return true;
}
return false;
}
void lineDetectionE(const Mat& src, std::vector<SEGMENT>& segments_all)
{
int r, c;
imageheight = src.rows; imagewidth = src.cols;
std::vector<Point2i> points;
std::vector<SEGMENT> segments, segments_tmp;
Mat canny;
if (canny_aperture_size == 0)
{
canny = src;
}
else
{
Canny(src, canny, canny_th1, canny_th2, canny_aperture_size);
}
canny.colRange(0, 6).rowRange(0, 6) = 0;
canny.colRange(src.cols - 5, src.cols).rowRange(src.rows - 5, src.rows) = 0;
SEGMENT seg, seg1, seg2;
for (r = 0; r < imageheight; r++)
{
for (c = 0; c < imagewidth; c++)
{
// Find seeds - skip for non-seeds
if (canny.at<unsigned char>(r, c) == 0)
continue;
// Found seeds
Point2i pt = Point2i(c, r);
points.push_back(pt);
canny.at<unsigned char>(pt.y, pt.x) = 0;
float direction = 0.0f;
int step = 0;
while (getPointChainE(canny, pt, pt, direction, step))
{
points.push_back(pt);
step++;
canny.at<unsigned char>(pt.y, pt.x) = 0;
}
if (points.size() < (unsigned int)threshold_length + 1)
{
points.clear();
continue;
}
extractSegmentsE(points, segments);
if (segments.size() == 0)
{
points.clear();
continue;
}
for (int i = 0; i < (int)segments.size(); i++)
{
seg = segments[i];
float length = sqrt((seg.x1 - seg.x2)*(seg.x1 - seg.x2) +
(seg.y1 - seg.y2)*(seg.y1 - seg.y2));
if (length < threshold_length)
continue;
if ((seg.x1 <= 5.0f && seg.x2 <= 5.0f) ||
(seg.y1 <= 5.0f && seg.y2 <= 5.0f) ||
(seg.x1 >= imagewidth - 5.0f && seg.x2 >= imagewidth - 5.0f) ||
(seg.y1 >= imageheight - 5.0f && seg.y2 >= imageheight - 5.0f))
continue;
additionalOperationsOnSegmentE(src, seg);
if (!do_merge)
segments_all.push_back(seg);
segments_tmp.push_back(seg);
}
points.clear();
segments.clear();
}
}
if (!do_merge)
return;
bool is_merged = false;
int ith = (int)segments_tmp.size() - 1;
int jth = ith - 1;
while (ith > 1 || jth > 0)
{
seg1 = segments_tmp[ith];
seg2 = segments_tmp[jth];
SEGMENT seg_merged;
is_merged = mergeSegmentsE(seg1, seg2, seg_merged);
if (is_merged == true)
{
seg2 = seg_merged;
additionalOperationsOnSegmentE(src, seg2);
std::vector<SEGMENT>::iterator it = segments_tmp.begin() + ith;
*it = seg2;
segments_tmp.erase(segments_tmp.begin() + jth);
ith--;
jth = ith - 1;
}
else
{
jth--;
}
if (jth < 0) {
ith--;
jth = ith - 1;
}
}
segments_all = segments_tmp;
}
static inline void getAngleE(SEGMENT& seg)
{
seg.angle = (float)(fastAtan2(seg.y2 - seg.y1, seg.x2 - seg.x1) / 180.0f * CV_PI);
}
static void additionalOperationsOnSegmentE(const Mat& src, SEGMENT& seg)
{
if (seg.x1 == 0.0f && seg.x2 == 0.0f && seg.y1 == 0.0f && seg.y2 == 0.0f)
return;
getAngleE(seg);
double ang = (double)seg.angle;
Point2f start = Point2f(seg.x1, seg.y1);
Point2f end = Point2f(seg.x2, seg.y2);
double dx = 0.0, dy = 0.0;
dx = (double)end.x - (double)start.x;
dy = (double)end.y - (double)start.y;
int num_points = 10;
Point2f *points = new Point2f[num_points];
points[0] = start;
points[num_points - 1] = end;
for (int i = 0; i < num_points; i++)
{
if (i == 0 || i == num_points - 1)
continue;
points[i].x = points[0].x + ((float)dx / float(num_points - 1) * (float)i);
points[i].y = points[0].y + ((float)dy / float(num_points - 1) * (float)i);
}
Point2i *points_right = new Point2i[num_points];
Point2i *points_left = new Point2i[num_points];
double gap = 1.0;
for (int i = 0; i < num_points; i++)
{
points_right[i].x = cvRound(points[i].x + gap*cos(90.0 * CV_PI / 180.0 + ang));
points_right[i].y = cvRound(points[i].y + gap*sin(90.0 * CV_PI / 180.0 + ang));
points_left[i].x = cvRound(points[i].x - gap*cos(90.0 * CV_PI / 180.0 + ang));
points_left[i].y = cvRound(points[i].y - gap*sin(90.0 * CV_PI / 180.0 + ang));
pointInboardTestE(src, points_right[i]);
pointInboardTestE(src, points_left[i]);
}
int iR = 0, iL = 0;
for (int i = 0; i < num_points; i++)
{
iR += src.at<unsigned char>(points_right[i].y, points_right[i].x);
iL += src.at<unsigned char>(points_left[i].y, points_left[i].x);
}
if (iR > iL)
{
std::swap(seg.x1, seg.x2);
std::swap(seg.y1, seg.y2);
getAngleE(seg);
}
delete[] points;
delete[] points_right;
delete[] points_left;
return;
}
void drawSegmentE(Mat& mat, const SEGMENT& seg, Scalar bgr, int thickness, bool directed)
{
double gap = 10.0;
double ang = (double)seg.angle;
double arrow_angle = 30.0;
Point2i p1;
p1.x = cvRound(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang));
p1.y = cvRound(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang));
pointInboardTestE(mat, p1);
line(mat, Point(cvRound(seg.x1), cvRound(seg.y1)),
Point(cvRound(seg.x2), cvRound(seg.y2)), bgr, thickness, 1);
if (directed)
line(mat, Point(cvRound(seg.x2), cvRound(seg.y2)), p1, bgr, thickness, 1);
}
int eyemEDLinesDetector(EyemImage tpImage, int _gradThresh, int _anchorThresh, int _scanInterval, int _minPathLen, double _sigma, bool _sumFlag, double _line_error, int _min_line_len, double _max_distance_between_two_lines, double _max_error, EyemImage *tpDstImg)
{
cv::Mat src = cv::Mat(tpImage.iHeight, tpImage.iWidth, tpImage.iDepth, tpImage.vpImage);
if (src.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
std::vector<cv::Vec4f> lines;
detectE(src, lines);
return FUNC_OK;
}
\ No newline at end of file
#pragma once
//
// eyemSmooth¡¤±êÍ·
//
#ifndef __EYEM_EDLINES_H
#define __EYEM_EDLINES_H
#include "eyemLib.h"
#include <algorithm>
#include <map>
using namespace cv;
struct SEGMENT
{
float x1, y1, x2, y2, angle;
};
/**
* Detect lines in the input image.
*
* @param _image A grayscale(CV_8UC1) input image.
* If only a roi needs to be selected, use
* lsd_ptr->detect(image(roi), ..., lines);
* lines += Scalar(roi.x, roi.y, roi.x, roi.y);
* @param _lines Return: A vector of Vec4f elements specifying the beginning and ending point of
* a line. Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 is the end.
* Returned lines are directed so that the brighter side is placed on left.
*/
void detectE(cv::InputArray _image, cv::OutputArray _lines);
/**
* Draw lines on the given canvas.
*
* @param image The image, where lines will be drawn
* Should have the size of the image, where the lines were found
* @param lines The lines that need to be drawn
* @param draw_arrow If true, arrow heads will be drawn
*/
void drawSegmentsE(cv::InputOutputArray _image, cv::InputArray lines, bool draw_arrow = false);
int imagewidth, imageheight, threshold_length;
float threshold_dist;
double canny_th1, canny_th2;
int canny_aperture_size;
bool do_merge;
//template<class T>
//void incidentPoint(const Mat& l, T& pt);
void mergeLinesE(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged);
bool mergeSegmentsE(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged);
bool getPointChainE(const cv::Mat& img, cv::Point pt, cv::Point& chained_pt, float& direction, int step);
double distPointLineE(const cv::Mat& p, cv::Mat& l);
void extractSegmentsE(const std::vector<cv::Point2i>& points, std::vector<SEGMENT>& segments);
void lineDetectionE(const cv::Mat& src, std::vector<SEGMENT>& segments_all);
void pointInboardTestE(const cv::Mat& src, cv::Point2i& pt);
inline void getAngleE(SEGMENT& seg);
void additionalOperationsOnSegmentE(const cv::Mat& src, SEGMENT& seg);
void drawSegmentE(cv::Mat& mat, const SEGMENT& seg, cv::Scalar bgr = cv::Scalar(0, 255, 0),
int thickness = 1, bool directed = true);
#endif/* __EYEM_EDLINES_H */
\ No newline at end of file
#include"eyemEdge.h"
void thinningIteration(cv::Mat& img, int iter)
{
CV_Assert(img.channels() == 1);
CV_Assert(img.depth() != sizeof(uchar));
CV_Assert(img.rows > 3 && img.cols > 3);
cv::Mat marker = cv::Mat::zeros(img.size(), CV_8UC1);
int nRows = img.rows;
int nCols = img.cols;
if (img.isContinuous()) {
nCols *= nRows;
nRows = 1;
}
int x, y;
uchar *pAbove;
uchar *pCurr;
uchar *pBelow;
uchar *nw, *no, *ne; // north (pAbove)
uchar *we, *me, *ea;
uchar *sw, *so, *se; // south (pBelow)
uchar *pDst;
// initialize row pointers
pAbove = NULL;
pCurr = img.ptr<uchar>(0);
pBelow = img.ptr<uchar>(1);
for (y = 1; y < img.rows - 1; ++y) {
// shift the rows up by one
pAbove = pCurr;
pCurr = pBelow;
pBelow = img.ptr<uchar>(y + 1);
pDst = marker.ptr<uchar>(y);
// initialize col pointers
no = &(pAbove[0]);
ne = &(pAbove[1]);
me = &(pCurr[0]);
ea = &(pCurr[1]);
so = &(pBelow[0]);
se = &(pBelow[1]);
for (x = 1; x < img.cols - 1; ++x) {
// shift col pointers left by one (scan left to right)
nw = no;
no = ne;
ne = &(pAbove[x + 1]);
we = me;
me = ea;
ea = &(pCurr[x + 1]);
sw = so;
so = se;
se = &(pBelow[x + 1]);
int A = (*no == 0 && *ne == 1) + (*ne == 0 && *ea == 1) +
(*ea == 0 && *se == 1) + (*se == 0 && *so == 1) +
(*so == 0 && *sw == 1) + (*sw == 0 && *we == 1) +
(*we == 0 && *nw == 1) + (*nw == 0 && *no == 1);
int B = *no + *ne + *ea + *se + *so + *sw + *we + *nw;
int m1 = iter == 0 ? (*no * *ea * *so) : (*no * *ea * *we);
int m2 = iter == 0 ? (*ea * *so * *we) : (*no * *so * *we);
if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
pDst[x] = 1;
}
}
img &= ~marker;
}
static void thinning(const cv::Mat& src, cv::Mat& dst)
{
dst = src.clone();
dst /= 255; // convert to binary image
cv::Mat prev = cv::Mat::zeros(dst.size(), CV_8UC1);
cv::Mat diff;
do {
thinningIteration(dst, 0);
thinningIteration(dst, 1);
cv::absdiff(dst, prev, diff);
dst.copyTo(prev);
} while (cv::countNonZero(diff) > 0);
dst *= 255;
}
int eyemEdgesPixel(EyemImage tpImage, double dThresh)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
int X = image.cols, Y = image.rows;
uchar *upF = image.data;
/*计算偏导*/
double *dpFx = (double *)malloc(X*Y * sizeof(double));
double *dpFy = (double *)malloc(X*Y * sizeof(double));
/*梯度幅值*/
double *dpMag = (double *)malloc(X*Y * sizeof(double));
cv::parallel_for_(cv::Range(1, Y - 1), [&](const cv::Range& range) -> void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 1; x < X - 1; x++)
{
dpFx[(x)+(y)*X] = 0.5*((double)(upF[(x + 1) + (y)*X]) - (double)(upF[(x - 1) + (y)*X]));
dpFy[(x)+(y)*X] = 0.5*((double)(upF[(x)+(y + 1)*X]) - (double)(upF[(x)+(y - 1)*X]));
dpMag[(x)+(y)*X] = sqrt(dpFx[(x)+(y)*X] * dpFx[(x)+(y)*X] + dpFy[(x)+(y)*X] * dpFy[(x)+(y)*X]);
}
}
});
unsigned char *ucpLabel = (unsigned char *)malloc(X*Y * sizeof(unsigned char));
memset(ucpLabel, 0, X*Y * sizeof(unsigned char));
cv::Mat label = cv::Mat(Y, X, CV_8UC1, ucpLabel);
cv::parallel_for_(cv::Range(1, Y - 1), [&](const cv::Range& range) -> void {
for (int y = range.start; y < range.end; y++)
for (int x = 1; x < (X - 1); x++)
{
if (dpMag[(x)+(y)*X] > dThresh)
{
//判断边缘
if (abs(dpFy[(x)+(y)*X]) >= abs(dpFx[(x)+(y)*X]) &&
abs(dpFy[(x)+(y)*X]) >= abs(dpFy[(x)+(y - 1)*X]) && abs(dpFy[(x)+(y)*X]) > abs(dpFy[(x)+(y + 1)*X]))
{
ucpLabel[(x)+(y)*X] = 255;//垂直边缘-2
}
else if (abs(dpFx[(x)+(y)*X]) > abs(dpFy[(x)+(y)*X]) &&
abs(dpFx[(x)+(y)*X]) >= abs(dpFx[(x - 1) + (y)*X]) && abs(dpFx[(x)+(y)*X]) > abs(dpFx[(x + 1) + (y)*X]))
{
ucpLabel[(x)+(y)*X] = 255;//水平边缘-1
}
}
}
});
//标记连通域
cv::Mat labels;
int ilabel = cv::connectedComponents(label, labels);
//绘制连通域
std::vector<cv::Vec3b> labelColor(ilabel);
for (int i = 0; i < ilabel; i++)
{
labelColor[i] = cv::Vec3b(rand() % 256, rand() % 256, rand() % 256);
}
cv::Mat labelImage;
cv::cvtColor(image, labelImage, cv::COLOR_GRAY2BGR);
for (int y = 1; y < Y - 1; y++)
{
for (int x = 1; x < X - 1; x++)
{
int lb = labels.at<int>(y, x);
if (lb != 0)
{
labelImage.at<cv::Vec3b>(y, x) = labelColor[lb];
}
}
}
//释放资源
free((void *)ucpLabel);
free((void *)dpFx);
free((void *)dpFy);
free((void *)dpMag);
return FUNC_OK;
}
int eyemEdgesSubpixel(EyemImage tpImage, int iFilter, int iLow, int iHigh)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
int X = image.cols, Y = image.rows;
uchar *upF = image.data;
/*计算偏导*/
double *dpFx = (double *)malloc(X*Y * sizeof(double));
double *dpFy = (double *)malloc(X*Y * sizeof(double));
/*梯度幅值*/
double *dpMag = (double *)malloc(X*Y * sizeof(double));
cv::parallel_for_(cv::Range(1, Y - 1), [&](const cv::Range& range) -> void {
for (int y = range.start; y < range.end; y++)
{
for (int x = 1; x < X - 1; x++)
{
dpFx[(x)+(y)*X] = 0.5*((double)(upF[(x + 1) + (y)*X]) - (double)(upF[(x - 1) + (y)*X]));
dpFy[(x)+(y)*X] = 0.5*((double)(upF[(x)+(y + 1)*X]) - (double)(upF[(x)+(y - 1)*X]));
dpMag[(x)+(y)*X] = sqrt(dpFx[(x)+(y)*X] * dpFx[(x)+(y)*X] + dpFy[(x)+(y)*X] * dpFy[(x)+(y)*X]);
}
}
});
unsigned char *ucpLabel = (unsigned char *)malloc(X*Y * sizeof(unsigned char));
memset(ucpLabel, 0, X*Y * sizeof(unsigned char));
cv::Mat label = cv::Mat(Y, X, CV_8UC1, ucpLabel);
cv::parallel_for_(cv::Range(1, Y - 1), [&](const cv::Range& range) -> void {
for (int y = range.start; y < range.end; y++)
for (int x = 1; x < (X - 1); x++)
{
if (dpMag[(x)+(y)*X] > 25)
{
//判断边缘
if (abs(dpFy[(x)+(y)*X]) >= abs(dpFx[(x)+(y)*X]) &&
abs(dpFy[(x)+(y)*X]) >= abs(dpFy[(x)+(y - 1)*X]) && abs(dpFy[(x)+(y)*X]) > abs(dpFy[(x)+(y + 1)*X]))
{
ucpLabel[(x)+(y)*X] = 255;//垂直边缘-2
}
else if (abs(dpFx[(x)+(y)*X]) > abs(dpFy[(x)+(y)*X]) &&
abs(dpFx[(x)+(y)*X]) >= abs(dpFx[(x - 1) + (y)*X]) && abs(dpFx[(x)+(y)*X]) > abs(dpFx[(x + 1) + (y)*X]))
{
ucpLabel[(x)+(y)*X] = 255;//水平边缘-1
}
}
}
});
cv::Mat labels;
cv::connectedComponents(label, labels);
//所有边缘
EyemOcsDXY temp;
std::vector<EyemOcsDXY> edges;
cv::parallel_for_(cv::Range(1, Y - 1), [&](const cv::Range& range) -> void {
for (int y = range.start; y < range.end; y++)
for (int x = 1; x < (X - 1); x++)
{
if (ucpLabel[(x)+(y)*X] != 0)
{
//判断边缘
if (abs(dpFy[(x)+(y)*X]) >= abs(dpFx[(x)+(y)*X]) &&
abs(dpFy[(x)+(y)*X]) >= abs(dpFy[(x)+(y - 1)*X]) && abs(dpFy[(x)+(y)*X]) > abs(dpFy[(x)+(y + 1)*X]))
{
//垂直边缘
double a, b, c, u;
a = dpMag[(x)+(y - 1)*X];
b = dpMag[(x)+(y)*X];
c = dpMag[(x)+(y + 1)*X];
u = 0.5*(a - c) / (a - b - b + c);
temp.dX = (float)x + 0.5f;
temp.dY = (float)y + 0.5f + (float)u;
edges.push_back(temp);
}
else if (abs(dpFx[(x)+(y)*X]) > abs(dpFy[(x)+(y)*X]) &&
abs(dpFx[(x)+(y)*X]) >= abs(dpFx[(x - 1) + (y)*X]) && abs(dpFx[(x)+(y)*X]) > abs(dpFx[(x + 1) + (y)*X]))
{
//水平边缘
double a, b, c, u;
a = dpMag[(x - 1) + (y)*X];
b = dpMag[(x)+(y)*X];
c = dpMag[(x + 1) + (y)*X];
u = 0.5*(a - c) / (a - b - b + c);
temp.dX = (float)x + 0.5f + (float)u;
temp.dY = (float)y + 0.5f;
edges.push_back(temp);
}
}
}
});
//cv::RNG rng;
//cv::Mat show;
//cv::cvtColor(image.clone(), show, cv::COLOR_GRAY2BGR);
//int cnt = 0;
//for (int i = 0; i < contours.size(); i++)
//{
// cv::Vec3b color = cv::Vec3b(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
// for (int j = 0; j < contours[i].size(); j++)
// {
// cnt++;
// show.at<cv::Vec3b>(contours[i][j]) = color;
// }
// //drawContours(show, contours, i, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 3);
//}
//释放资源
free((void *)ucpLabel);
free((void *)dpFx);
free((void *)dpFy);
free((void *)dpMag);
return FUNC_OK;
}
int eyemSobelAmp(EyemImage tpImage, EyemImage &ImaAmp)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat dx, dy;
cv::spatialGradient(image, dx, dy);
cv::Mat mag;
cv::magnitude(dx, dy, mag);
return FUNC_OK;
}
int eyemSkeleton(EyemImage tpImage, cv::Mat &skeleton)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
thinning(image, skeleton);
return FUNC_OK;
}
int eyemAutoCanny(EyemImage tpImage, double dSigma = 0.33)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat F;
cv::GaussianBlur(image, F, cv::Size(3, 3), 0, 0);
////get the median value of the matrix
//double v = medianMat(output);
////generate the thresholds
//int lower = (int)std::max(0.0, (1, 0 - sigma)*v);
//int upper = (int)std::min(255.0, (1, 0 + sigma)*v);
////apply canny operator
//cv::Canny(output, output, lower, upper, 3);
return FUNC_OK;
}
#pragma once
//
// eyemEdgeͷ
//
#ifndef __EYEM_EDGE_H
#define __EYEM_EDGE_H
#include "eyemLib.h"
#include "eyemGeneric.h"
#endif/* __EYEM_EDGE_H */
\ No newline at end of file
#include "eyemEdge1d.h"
static void findPeak(std::vector<double> vec, std::vector<int>& peaks)
{
std::vector<int> sign;
for (int i = 1; i < vec.size(); i++)
{
auto diff = vec[i] - vec[i - 1];
if (diff < .0)
{
sign.push_back(-1);
}
else if (diff > .0)
{
sign.push_back(1);
}
else
{
sign.push_back(0);
}
}
for (int j = 1; j < sign.size(); j++)
{
int diff = sign[j] - sign[j - 1];
if (diff != 0)
{
peaks.push_back(j);
}
}
}
static cv::Mat projectMap(const cv::Mat map, int threshold)
{
double height = .0, width = map.cols;
cv::Mat temp;
cv::normalize(map, temp, 0, 255, cv::NORM_MINMAX);
cv::minMaxLoc(temp, NULL, &height, NULL, NULL);
cv::Mat image = cv::Mat::zeros((int)height, (int)width, CV_8UC3);
image.setTo(cv::Scalar(100, 0, 0));
std::vector<cv::Point> rejectPoint;
for (int i = 0; i < temp.cols; i++)
{
rejectPoint.push_back(cv::Point(i, (int)(height - temp.at<double>(cv::Point(i, 0)))));
}
cv::polylines(image, rejectPoint, false, cv::Scalar(0, 255, 0), 1, 8, 0);
cv::line(image, cv::Point(0, (int)MAX(height - threshold, 0)), cv::Point((int)width, (int)MAX(height - threshold, 0)), cv::Scalar(0, 255, 255), 1, 8);
return image;
}
static void interp2(cv::Mat& src, cv::Mat& dst, cv::Mat& map1, cv::Mat& map2)
{
}
int eyemEdge1dGenMeasureRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, const char *ccSubType, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>tpImage.iWidth || tpLineSt.dY>tpImage.iHeight\
|| tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>tpImage.iWidth || tpLineEd.dY>tpImage.iHeight)
return FUNC_ILLEGAL_ARGUMENT;
//主轴倾斜角
double t = .0;
t = atan2(tpLineEd.dY - tpLineSt.dY, tpLineEd.dX - tpLineSt.dX) * 180. / PI;
double rotWeight = tpImage.iHeight * abs(sin(t * CV_PI / 180)) + tpImage.iWidth * abs(cos(t * CV_PI / 180));
double rotHeight = ceil(tpImage.iWidth * abs(sin(t * CV_PI / 180)) + tpImage.iHeight * abs(cos(t * CV_PI / 180)));
cv::RotatedRect rotRect(cv::Point2f((float)(tpLineSt.dX + tpLineEd.dX) / 2.0f, (float)(tpLineSt.dY + tpLineEd.dY) / 2.0f), \
cv::Size2f((float)std::sqrt(std::pow(tpLineSt.dX - tpLineEd.dX, 2) + (float)std::pow(tpLineSt.dY - tpLineEd.dY, 2)), (float)iWhRoi), (float)t);
cv::Mat rotM2d(2, 3, CV_64F);
rotM2d = cv::getRotationMatrix2D(cv::Point2f(tpImage.iWidth / 2.0f - 0.5f, tpImage.iHeight / 2.0f - 0.5f), t, 1.0);
#define COEFF_AT(x,y) ((double *)rotM2d.data)[(y)*rotM2d.cols + (x)]
COEFF_AT(2, 0) += (rotWeight - tpImage.iWidth) / 2.0;
COEFF_AT(2, 1) += (rotHeight - tpImage.iHeight) / 2.0;
cv::Point2d rotedCenter;
rotedCenter.x = rotRect.center.x*COEFF_AT(0, 0) + rotRect.center.y*COEFF_AT(1, 0) + COEFF_AT(2, 0);
rotedCenter.y = rotRect.center.x* COEFF_AT(0, 1) + rotRect.center.y*COEFF_AT(1, 1) + COEFF_AT(2, 1);
cv::Mat rotImg;
cv::warpAffine(image, rotImg, rotM2d, cv::Size((int)rotWeight, (int)rotHeight), cv::INTER_LINEAR);
//获取Roi区域
cv::Rect roi((int)MAX(rotedCenter.x - rotRect.size.width / 2, 0), (int)MAX(rotedCenter.y - rotRect.size.height / 2, 0), \
(int)rotRect.size.width, (int)rotRect.size.height);
cv::Mat filter, diffMat, one;
diffMat = convert(rotImg(roi), CV_64F);
//计算投影
cv::reduce(diffMat, one, 0, cv::REDUCE_AVG, CV_64F);
#ifdef _DEBUG
cv::Mat map1 = projectMap(one, 30);
#endif
//高斯滤波
cv::Mat kernel = cv::getGaussianKernel(5, dSigma).t();
cv::sepFilter2D(one, one, diffMat.depth(), kernel, cv::Mat::ones(1, 1, CV_64F));
#ifdef _DEBUG
cv::Mat map2 = projectMap(one, 30);
#endif
//默认过滤一半像素
const cv::Mat whalf = (cv::Mat_<double>(1, 5) << -1, -1, 0, 1, 1);
cv::sepFilter2D(one, filter, diffMat.depth(), whalf, cv::Mat::ones(1, 1, CV_64F));
#ifdef _DEBUG
cv::Mat map3 = projectMap(filter, 130);
#endif
std::vector<double> v_filter = filter.reshape(0, 1);
std::vector<int> peeks;
findPeak(v_filter, peeks);
std::vector<EyemOcsDXY> *tpEdges = new std::vector<EyemOcsDXY>();
EyemOcsDXY tpEdge;
for (int i = 0; i < (int)peeks.size(); i++)
{
if (abs(v_filter[peeks[i]]) > dAmpThresh)
{
double a, b, c;
a = v_filter[MAX(0, peeks[i] - 1)];
b = v_filter[peeks[i]];
c = v_filter[MIN((int)v_filter.size() - 1, peeks[i] + 1)];
double offset = 0.5 * (a - c) / (a - b - b + c);
if (abs(offset) <= 0.5)
{
double x = peeks[i] + rotedCenter.x - rotRect.size.width / 2 + offset + 0.5;
double y = iWhRoi / 2 + rotedCenter.y - rotRect.size.height / 2 + 0.5;
double a1, b1, c1, a2, b2, c2;
a1 = COEFF_AT(0, 0); b1 = COEFF_AT(1, 0); c1 = x - COEFF_AT(2, 0);
a2 = COEFF_AT(0, 1); b2 = COEFF_AT(1, 1); c2 = y - COEFF_AT(2, 1);
tpEdge.dX = (c1*b2 - c2*b1) / (a1*b2 - a2*b1);
tpEdge.dY = (c1*a2 - c2*a1) / (b1*a2 - b2*a1);
//all
if (iTransition == 0)
{
tpEdges->push_back(tpEdge);
}
else if (iTransition == 1)
{
//positive
if (b < 0)
{
tpEdges->push_back(tpEdge);
}
}
else if (iTransition == -1)
{
//negative
if (b > 0)
{
tpEdges->push_back(tpEdge);
}
}
}
}
}
if (strcmp(ccSubType, "first") == 0)
{
tpEdge = tpEdges->front();
tpEdges->clear();
tpEdges->push_back(tpEdge);
}
else if (strcmp(ccSubType, "last") == 0)
{
tpEdge = tpEdges->back();
tpEdges->clear();
tpEdges->push_back(tpEdge);
}
#ifdef _DEBUG
std::cout << "Test 'eyemEdge1dGenRect' " << std::endl;
cv::Mat showMat, showMat2;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2BGR);
cv::Point2f rect[4];
rotRect.points(rect);
for (int j = 0; j < 4; j++)
{
cv::line(showMat, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 255, 0), 1);
}
//获取ROI区域
cv::cvtColor(rotImg.clone(), showMat2, cv::COLOR_GRAY2BGR);
cv::rectangle(showMat2, roi, cv::Scalar(0, 255, 0), 1);
cv::line(showMat, cv::Point((int)tpLineSt.dX, (int)tpLineSt.dY), cv::Point((int)tpLineEd.dX, (int)tpLineEd.dY), cv::Scalar(0, 255, 0), 1);
for (int i = 0; i < tpEdges->size(); i++)
{
double _angle = (t + 90.)*CV_PI / 180.;
float b = (float)cos(_angle)*0.5f;
float a = (float)sin(_angle)*0.5f;
cv::Point2f center((float)tpEdges->at(i).dX, (float)tpEdges->at(i).dY);
cv::Point start((int)(center.x - b*iWhRoi + 0.5), (int)(center.y - a*iWhRoi + 0.5));
cv::Point end((int)(center.x + b*iWhRoi + 0.5), (int)(center.y + a*iWhRoi + 0.5));
cv::line(showMat, start, end, cv::Scalar(0, 0, 255), 1);
}
#endif
*hObject = reinterpret_cast<IntPtr>(tpEdges);
return FUNC_OK;
}
int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>tpImage.iWidth || tpLineSt.dY>tpImage.iHeight\
|| tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>tpImage.iWidth || tpLineEd.dY>tpImage.iHeight)
return FUNC_ILLEGAL_ARGUMENT;
//主轴倾角
double t = .0;
t = atan2(tpLineEd.dY - tpLineSt.dY, tpLineEd.dX - tpLineSt.dX) * 180. / PI;
double rotWeight = tpImage.iHeight * abs(sin(t * CV_PI / 180)) + tpImage.iWidth * abs(cos(t * CV_PI / 180));
double rotHeight = ceil(tpImage.iWidth * abs(sin(t * CV_PI / 180)) + tpImage.iHeight * abs(cos(t * CV_PI / 180)));
cv::RotatedRect rotRect(cv::Point2f((float)(tpLineSt.dX + tpLineEd.dX) / 2.0f, (float)(tpLineSt.dY + tpLineEd.dY) / 2.0f), \
cv::Size2f((float)std::sqrt(std::pow(tpLineSt.dX - tpLineEd.dX, 2) + (float)std::pow(tpLineSt.dY - tpLineEd.dY, 2)), (float)iWhRoi), (float)t);
cv::Mat rotM2d(2, 3, CV_64F);
rotM2d = cv::getRotationMatrix2D(cv::Point2f(tpImage.iWidth / 2.0f - 0.5f, tpImage.iHeight / 2.0f - 0.5f), t, 1.0);
#define COEFF_AT(x,y) ((double *)rotM2d.data)[(y)*rotM2d.cols + (x)]
COEFF_AT(2, 0) += (rotWeight - tpImage.iWidth) / 2.0;
COEFF_AT(2, 1) += (rotHeight - tpImage.iHeight) / 2.0;
cv::Point2d rotedCenter;
rotedCenter.x = rotRect.center.x*COEFF_AT(0, 0) + rotRect.center.y*COEFF_AT(1, 0) + COEFF_AT(2, 0);
rotedCenter.y = rotRect.center.x* COEFF_AT(0, 1) + rotRect.center.y*COEFF_AT(1, 1) + COEFF_AT(2, 1);
cv::Mat rotImg;
cv::warpAffine(image, rotImg, rotM2d, cv::Size((int)rotWeight, (int)rotHeight), cv::INTER_LINEAR);
//获取Roi区域
cv::Rect roi((int)MAX(rotedCenter.x - rotRect.size.width / 2, 0), (int)MAX(rotedCenter.y - rotRect.size.height / 2, 0), \
(int)rotRect.size.width, (int)rotRect.size.height);
cv::Mat F, G;
F = convert(rotImg(roi), CV_64F);
//高斯滤波
cv::GaussianBlur(F, G, cv::Size(3, 3), dSigma, dSigma);
//偏导
cv::Mat dx, dy;
spatialGradient(G, dx, dy);
//梯度幅值
cv::Mat mag;
cv::magnitude(dx, dy, mag);
#define FELEM_AT(x,y) ((double *)F.data)[(y)*F.cols + (x)]
#define FXELEM_AT(x,y) ((double *)dx.data)[(y)*dx.cols + (x)]
#define FYELEM_AT(x,y) ((double *)dy.data)[(y)*dy.cols + (x)]
#define MAGELEM_AT(x,y) ((double *)mag.data)[(y)*mag.cols + (x)]
//提取边缘
std::vector<cv::Point> edgePixel;
cv::parallel_for_(cv::Range(5, F.rows - 4), [&](const cv::Range& range) -> void {
for (int r = range.start; r < range.end; r++)
{
for (int c = 5; c < mag.cols - 4; c++)
{
if (MAGELEM_AT(c, r) > dAmpThresh)
{
if (abs(FYELEM_AT(c, r)) >= abs(FXELEM_AT(c, r)))
{
if (abs(FYELEM_AT(c, r)) >= abs(FYELEM_AT(c, r - 1))\
&&abs(FYELEM_AT(c, r)) >= abs(FYELEM_AT(c, r + 1)))
{
edgePixel.push_back(cv::Point(c, r));
}
}
else
{
if (abs(FXELEM_AT(c, r)) >= abs(FXELEM_AT(c - 1, r))\
&&abs(FXELEM_AT(c, r)) >= abs(FXELEM_AT(c + 1, r)))
{
edgePixel.push_back(cv::Point(c, r));
}
}
}
}
}
});
cv::Mat showMat3;
cv::cvtColor(convert(F, CV_8U), showMat3, cv::COLOR_GRAY2BGR);
EyemOcsDXY tpEdge;
std::vector<EyemOcsDXY> *tpEdges = new std::vector<EyemOcsDXY>();
for (int i = 0; i < (int)edgePixel.size(); i++)
{
double x = edgePixel[i].x + rotedCenter.x - rotRect.size.width / 2 + 0.5;
double y = edgePixel[i].y + rotedCenter.y - rotRect.size.height / 2 + 0.5;
double a1, b1, c1, a2, b2, c2;
a1 = COEFF_AT(0, 0); b1 = COEFF_AT(1, 0); c1 = x - COEFF_AT(2, 0);
a2 = COEFF_AT(0, 1); b2 = COEFF_AT(1, 1); c2 = y - COEFF_AT(2, 1);
tpEdge.dX = (c1*b2 - c2*b1) / (a1*b2 - a2*b1);
tpEdge.dY = (c1*a2 - c2*a1) / (b1*a2 - b2*a1);
tpEdges->push_back(tpEdge);
}
#ifdef _DEBUG
std::cout << "Test 'eyemEdge1dGenRect' " << std::endl;
cv::Mat showMat, showMat2;
cv::cvtColor(image, showMat, cv::COLOR_GRAY2BGR);
cv::Point2f rect[4];
rotRect.points(rect);
for (int j = 0; j < 4; j++)
{
cv::line(showMat, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 255, 0), 1);
}
//获取ROI区域
cv::cvtColor(rotImg.clone(), showMat2, cv::COLOR_GRAY2BGR);
cv::rectangle(showMat2, roi, cv::Scalar(0, 255, 0), 1);
cv::line(showMat, cv::Point((int)tpLineSt.dX, (int)tpLineSt.dY), cv::Point((int)tpLineEd.dX, (int)tpLineEd.dY), cv::Scalar(0, 255, 0), 1);
//for (int i = 0; i < edges.size(); i++)
//{
// showMat.at<cv::Vec3b>(cv::Point(edges[i].dX, edges[i].dY)) = cv::Vec3b(0, 0, 255);
// //cv::line(showMat, start, end, cv::Scalar(0, 0, 255), 1);
//}
#endif
*hObject = reinterpret_cast<IntPtr>(tpEdges);
return FUNC_OK;
}
int eyemEdge1dFitLine(IntPtr hObject, EyemOcsDABC *tpLine)
{
//根据导数符号确定由暗到明和由明到暗方向,执行圆拟合与直线拟合
//std::vector<EyemOcsDXY> *tpEdges = reinterpret_cast<std::vector<EyemOcsDXY>*>(hObject);
return FUNC_OK;
}
int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, IntPtr *hObject)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
if (tpLineSt.dX < 0 || tpLineSt.dY < 0 || tpLineSt.dX>tpImage.iWidth || tpLineSt.dY>tpImage.iHeight\
|| tpLineEd.dX<0 || tpLineEd.dY<0 || tpLineEd.dX>tpImage.iWidth || tpLineEd.dY>tpImage.iHeight)
return FUNC_ILLEGAL_ARGUMENT;
//主轴倾斜角
double t = .0, a = .0, b = .0, c = .0;
t = atan2(-tpLineEd.dX + tpLineSt.dX, tpLineEd.dY - tpLineSt.dY) /** 180. / PI*/;
//主轴直线方程ax+by+c=0
a = -(tpLineSt.dY - tpLineEd.dY);
b = (tpLineSt.dX - tpLineEd.dX);
c = tpLineEd.dX*tpLineSt.dY - tpLineSt.dX*tpLineEd.dY;
double x = (tpLineSt.dX + tpLineEd.dX) / 2;
double y = -(a*x + c) / b;
double *dpWhalf = new double[2 * iWhRoi + 1];
for (int i = -iWhRoi, j = 0; i <= iWhRoi, j < 2 * iWhRoi + 1; i++, j++)
{
dpWhalf[j] = i;
}
cv::Mat whalf(1, 2 * iWhRoi + 1, CV_64F, dpWhalf);
cv::Mat map1, map2;
//沿法线方向采样
map1 = whalf*cos(t);
map2 = whalf*sin(t);
map1 += cv::Mat::ones(1, 31, CV_64F)*x;
map2 += cv::Mat::ones(1, 31, CV_64F)*y;
cv::Mat dst;
interp2(image, dst, map1, map2);
cv::Mat cc;
cv::cvtColor(image, cc, cv::COLOR_GRAY2BGR);
for (int i = 0; i < 31; i++)
{
cc.at<cv::Vec3b>(cv::Point2f(map1.at<double>(0, i), map2.at<double>(0, i))) = cv::Vec3b(0, 255, 0);
}
return FUNC_OK;
}
int eyemEdge1dFitCircle(IntPtr hObject, int iClippingEndPoints, int iMaxIterations, double dRobustCoef, EyemOcsDXYR *tpCircle)
{
return FUNC_OK;
}
//int eyemEdge1dGenArc(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iEdgeDirec, EyemOcsDXY *tpEdge)
//{
//
// return FUNC_OK;
//}
bool eyemEdge1dGenMeasureFree(IntPtr hObject)
{
std::vector<EyemOcsDXY> *tpEdges = reinterpret_cast<std::vector<EyemOcsDXY>*>(hObject);
delete tpEdges;
tpEdges = NULL;
return true;
}
#pragma once
//
// eyemEdge1dͷ
//
#ifndef __EYEM_EDGE1D_H
#define __EYEM_EDGE1D_H
#include "eyemLib.h"
#include "eyemGeneric.h"
#endif/* __EYEM_EDGE1D_H */
\ No newline at end of file
#include "eyemFit.h"
static double calcDist(const EyemOcsDXY2D taPoint1, const EyemOcsDXYR taPoint2)
{
return std::sqrt(std::pow(taPoint2.dX - taPoint1.dX, 2) + std::pow(taPoint2.dY - taPoint1.dY, 2));
}
static double calcDist2D(const EyemOcsDXY2D taPointP, double dA, double dB, double dC)
{
return abs(dA*taPointP.dX + dB*taPointP.dY + dC) / sqrt(dA*dA + dB*dB);
}
static void weightL1(float *d, int count, float *w, float _c)
{
int i;
for (i = 0; i < count; i++)
{
double t = fabs((double)d[i]);
w[i] = (float)(1. / MAX(t, EPS));
}
}
static void weightL12(float *d, int count, float *w, float _c)
{
int i;
for (i = 0; i < count; i++)
{
w[i] = 1.0f / (float)std::sqrt(1 + (double)(d[i] * d[i] * 0.5));
}
}
static void weightFair(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 1 / 1.3998f : 1 / _c;
for (i = 0; i < count; i++)
{
w[i] = 1 / (1 + d[i] * c);
}
}
static void weightWelsch(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 1 / 2.9846f : 1 / _c;
for (i = 0; i < count; i++)
{
w[i] = (float)std::exp(-d[i] * d[i] * c * c);
}
}
static void weightHuber(float *d, int count, float *w, float _c)
{
int i;
const float c = _c <= 0 ? 1.345f : _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = 1.0f;
else
w[i] = c / fabs(d[i]);
}
}
static void weightTukey(float *d, int count, float *w, float _c)
{
int i;
const float c = _c <= 0 ? 2.718f : _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = std::pow(1.0f - (d[i] / c)*(d[i] / c), 2);
else
w[i] = .0f;
}
}
static void weightCauchy(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 1 / 2.385f : 1 / _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = 1 / (1 + d[i] * d[i] * c*c);
else
w[i] = .0;
}
}
static void weightLogistic(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 1 / 1.205f : 1 / _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = tanh(d[i] * c) / (d[i] * c);
else
w[i] = .0;
}
}
static void weightAndrews(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 1 / 1.339f : 1 / _c;
for (i = 0; i < count; i++)
{
if (d[i] < PI)
w[i] = sin(d[i] * c) / (d[i] * c);
else
w[i] = .0;
}
}
static void weightTalworth(float *d, int count, float *w, float _c)
{
int i;
const float c = _c == 0 ? 2.795f : _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = 1.;
else
w[i] = .0;
}
}
static void weightUser(float *d, int count, float *w, float _c)
{
int i;
const float c = _c <= 0 ? 2.718f : _c;
for (i = 0; i < count; i++)
{
if (d[i] < c)
w[i] = pow(1.0f - (d[i] / c)*(d[i] / c), 2);
else
w[i] = .0;
}
}
static int fitLine2D_wods(int iPtnNum, const EyemOcsDXY *taPoints, float *weights, float *line)
{
double px = .0, py = .0, w = .0;
double sa[4], sb[2], sx[2];
cv::Mat a = cv::Mat(2, 2, CV_64F, sa), b = cv::Mat(2, 1, CV_64F, sb);
cv::Mat x = cv::Mat(2, 1, CV_64F, sx);
std::memset(sa, 0, sizeof(sa));
std::memset(sb, 0, sizeof(sb));
std::memset(sx, 0, sizeof(sx));
for (int i = 0; i < iPtnNum; i++)
{
sa[0] += weights[i];
sa[1] += weights[i] * taPoints[i].dX;
sa[3] += weights[i] * taPoints[i].dX*taPoints[i].dX;
sb[0] += weights[i] * taPoints[i].dY;
sb[1] += weights[i] * taPoints[i].dX*taPoints[i].dY;
w += weights[i];
}
sa[2] = sa[1];
px = sa[1] / w, py = sb[0] / w;
//solve ax=b
bool solved = cv::solve(a, b, x, cv::DECOMP_SVD);
if (!solved)
return -100;
float t = (float)atan(sx[1]);
line[0] = (float)cos(t);
line[1] = (float)sin(t);
line[2] = (float)px;
line[3] = (float)py;
return 0;
}
int eyemRobustFitLine(int iPtnNum, EyemOcsDXY *taPoints, int iCalcMode, double dRobustCoef, EyemOcsDABC &tpLine)
{
double min_err = DBL_MAX, err = 0;
void(*calc_weights_param) (float *, int, float *, float) = 0;
float linebuf[4] = { .0f };
memset(linebuf, 0, 4 * sizeof(float));
std::vector<float> weights(iPtnNum, 1.0);
switch (iCalcMode)
{
case EYEM_DIST_L1:
calc_weights_param = weightL1;
break;
case EYEM_DIST_L12:
calc_weights_param = weightL12;
break;
case EYEM_DIST_FAIR:
calc_weights_param = weightFair;
break;
case EYEM_DIST_WELSCH:
calc_weights_param = weightWelsch;
break;
case EYEM_DIST_HUBER:
calc_weights_param = weightHuber;
break;
case EYEM_DIST_TUKEY:
calc_weights_param = weightTukey;
break;
case EYEM_DIST_CAUCHY:
calc_weights_param = weightCauchy;
break;
case EYEM_DIST_LOGISTIC:
calc_weights_param = weightLogistic;
break;
case EYEM_DIST_ANDREWS:
calc_weights_param = weightAndrews;
break;
case EYEM_DIST_ATLWORTH:
calc_weights_param = weightTalworth;
break;
case EYEM_DIST_USER:
calc_weights_param = weightUser;
break;
default:
break;
}
for (int it = 0; it < 50; it++)
{
float sum_dist = .0, sum_w = .0;
/*calculate parameter*/
int solved = fitLine2D_wods(iPtnNum, taPoints, &weights[0], linebuf);
if (solved != 0)
return FUNC_CANNOT_CALC;
float px = linebuf[2], py = linebuf[3];
float nx = linebuf[1], ny = -linebuf[0];
cv::AutoBuffer<float> dist(iPtnNum);
/*calculate distance*/
for (int k = 0; k < iPtnNum; k++)
{
dist[k] = fabs(nx*(float)taPoints[k].dX + ny*(float)taPoints[k].dY - (nx*px + ny*py)) / sqrt(nx*nx + ny*ny);
sum_dist += dist[k];
}
err = sum_dist;
if (sum_dist < FLT_EPSILON)
break;
/*calculate weight*/
calc_weights_param(dist, iPtnNum, &weights[0], (float)dRobustCoef);
if (std::abs(err - min_err) < FLT_EPSILON)
break;
min_err = err;
}
double px = linebuf[2], py = linebuf[3];
double nx = linebuf[1], ny = -linebuf[0];
//直线一般式
tpLine.dA = nx;
tpLine.dB = ny;
tpLine.dC = -(nx*px + ny*py);
//std::vector<cv::Point2f> points;
//for (int i = 0; i < iPtnNum; i++)
//{
// if (taPoint[i].bValid)
// {
// points.push_back(cv::Point2f((float)taPoint[i].dX, (float)taPoint[i].dY));
// }
//}
//double t = .0;
//cv::Vec4f line;
//cv::fitLine(points, line, iCalcMode, .0, 1e-2, 1e-2);
////ax+by+c=0
//t = atan2(line[1], line[0]);
//tpLine.dA = sin(t);
//tpLine.dB = -cos(t);
//tpLine.dC = -(sin(t)*line[2] - cos(t)*line[3]);
return FUNC_OK;
}
int fitCircle2D(int iPtnNum, EyemOcsDXY2D *taPoint, int iCalcMode, EyemOcsDXYR &tpCircle) {
if (iPtnNum <= 0) {
return 0;
}
std::vector<cv::Point2d> points;
for (int i = 0; i < iPtnNum; i++)
{
if (taPoint[i].bValid)
{
points.push_back(cv::Point2d(taPoint[i].dX, taPoint[i].dY));
}
}
//计算系数
double sa[9], sb[3], sx[3];
cv::Mat a = cv::Mat(3, 3, CV_64F, sa), b = cv::Mat(3, 1, CV_64F, sb);
//系数矩阵A*X=B;
cv::Mat x = cv::Mat(3, 1, CV_64F, sx);
std::memset(sa, 0, sizeof(sa));
std::memset(sb, 0, sizeof(sb));
for (int i = 0; i < iPtnNum; i++)
{
sa[0] += (double)points[i].x;
sa[1] += (double)points[i].y;
sa[2] += 1.0;
sa[3] += (double)points[i].x*(double)points[i].x;
sa[4] += (double)points[i].x*(double)points[i].y;
sa[7] += (double)points[i].y*(double)points[i].y;
sb[1] += (double)points[i].x*(-(double)points[i].x*(double)points[i].x - (double)points[i].y*(double)points[i].y);
sb[2] += (double)points[i].y*(-(double)points[i].x*(double)points[i].x - (double)points[i].y*(double)points[i].y);
}
sa[5] = sa[0];
sa[6] = sa[4];
sa[8] = sa[1];
sb[0] = -(sa[3] + sa[7]);
cv::solve(a, b, x, cv::DECOMP_SVD);
tpCircle.dX = -*x.ptr<double>(0) / 2.0;
tpCircle.dY = -*x.ptr<double>(1) / 2.0;
tpCircle.dR = sqrt(pow(*x.ptr<double>(0), 2) + pow(*x.ptr<double>(1), 2) - *x.ptr<double>(2));
return 1;
}
int eyemFitLine(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, int numToIgnore, EyemOcsDABC &tpLine)
{
//int maxiter = 50;
//double min_err = DBL_MAX, err = 0;
//if (numToIgnore > iPtnNum - 2 || iPtnNum < 2) {
// return FUNC_CANNOT_CALC;
//}
//EyemOcsDXY2D *taPoints = new EyemOcsDXY2D[iPtnNum];
//for (int i = 0; i < iPtnNum; i++)
//{
// taPoints[i].bValid = true;
// taPoints[i].dX = taPoint[i].dX;
// taPoints[i].dY = taPoint[i].dY;
// taPoints[i].dE = EPS;
//}
////Initialize the parameters with Robust method
//fitLine2D(iPtnNum, taPoints, iCalcMode, tpLine);
//for (int it = 0; it < maxiter; it++)
//{
// double sr = 0.0, r = 0.0;
// /* calculate distances */
// for (int i = 0; i < iPtnNum; i++)
// {
// taPoints[i].bValid = true;
// taPoints[i].dE = std::pow(calcDist2D(taPoints[i], tpLine.dA, tpLine.dB, tpLine.dC), 2);
// }
// //sort by dE
// std::sort(taPoints, taPoints + iPtnNum, std::less<EyemOcsDXY2D>());
// for (int i = (iPtnNum - numToIgnore); i < iPtnNum; i++)
// {
// taPoints[i].bValid = false;
// }
// /* Run again... */
// fitLine2D(iPtnNum, taPoints, iCalcMode, tpLine);
// for (int i = 0; i < iPtnNum; i++)
// {
// if (taPoints[i].bValid)
// {
// r = std::pow(calcDist2D(taPoints[i], tpLine.dA, tpLine.dB, tpLine.dC), 2);
// sr += r;
// }
// }
// err = std::sqrt(sr / (double)(iPtnNum - numToIgnore));
// if (err < EPS)
// break;
// if (std::abs(err - min_err) < EPS)
// break;
// min_err = err;
//}
////free memory
//delete[] taPoints;
//taPoints = NULL;
return FUNC_OK;
}
int eyemFitCircle(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, int numToIgnore, EyemOcsDXYR &tpCircle)
{
int maxiter = 50;
double min_err = DBL_MAX, err = 0;
if (numToIgnore > iPtnNum - 3 || iPtnNum < 3) {
return FUNC_CANNOT_CALC;
}
EyemOcsDXY2D *taPoints = new EyemOcsDXY2D[iPtnNum];
for (int i = 0; i < iPtnNum; i++)
{
taPoints[i].bValid = true;
taPoints[i].dX = taPoint[i].dX;
taPoints[i].dY = taPoint[i].dY;
taPoints[i].dE = EPS;
}
//初始化参数,或许可用RANSAC算法进一步提高鲁棒性,不过没必要
fitCircle2D(iPtnNum, taPoints, iCalcMode, tpCircle);
//迭代计算
for (int it = 0; it < maxiter; it++)
{
double sr = 0.0, r = 0.0;
for (int i = 0; i < iPtnNum; i++)
{
taPoints[i].bValid = true;
taPoints[i].dE = std::pow(calcDist(taPoints[i], tpCircle) - tpCircle.dR, 2);
}
//排序
std::sort(taPoints, taPoints + iPtnNum, std::less<EyemOcsDXY2D>());
//忽略的点
for (int i = (iPtnNum - numToIgnore); i < iPtnNum; i++)
{
taPoints[i].bValid = false;
}
/*Run again...*/
fitCircle2D(iPtnNum, taPoints, iCalcMode, tpCircle);
//计算RMS
for (int i = 0; i < iPtnNum; i++)
{
if (taPoints[i].bValid)
{
r = std::pow(calcDist(taPoints[i], tpCircle) - tpCircle.dR, 2);
sr += r;
}
}
err = std::sqrt(sr / (double)(iPtnNum - numToIgnore));
if (err < EPS)
break;
if (std::abs(err - min_err) < EPS)
break;
min_err = err;
}
//free memory
delete[] taPoints;
taPoints = NULL;
return FUNC_OK;
}
#pragma once
//
// eyemFit·标头
//
#ifndef __EYEM_FIT_H
#define __EYEM_FIT_H
#include "eyemLib.h"
struct EyemOcsDXY2D {
double dE; //误差类似于计分功能,越小分数越高
double dX, dY; //坐标位置
bool bValid = true; //指示该点是否参与计算
EyemOcsDXY2D() {}
EyemOcsDXY2D(double dE, double dX, double dY, bool bValid) :dE(dE), dX(dX), dY(dY), bValid(bValid) {}
bool operator <(const EyemOcsDXY2D &te)const
{
return dE < te.dE;
}
bool operator >(const EyemOcsDXY2D &te)const
{
return dE > te.dE;
}
};
struct EyemOcsDXYZ3D {
double dE; //误差类似于计分功能,越小分数越高
double dX, dY, dZ; //坐标位置
bool bValid = true; //指示该点是否参与计算
EyemOcsDXYZ3D() {}
EyemOcsDXYZ3D(double dE, double dX, double dY, double dZ, bool bValid) :dE(dE), dX(dX), dY(dY), dZ(dZ), bValid(bValid) {}
bool operator <(const EyemOcsDXYZ3D &te)const
{
return dE < te.dE;
}
bool operator >(const EyemOcsDXYZ3D &te)const
{
return dE > te.dE;
}
};
#endif/* __EYEM_FIT_H */
\ No newline at end of file
#include "eyemGeneric.h"
cv::Mat convert(cv::Mat& src, const int depth)
{
cv::Mat ret;
src.convertTo(ret, depth);
return ret;
}
void spatialGradient(cv::Mat src, cv::Mat &dx, cv::Mat &dy)
{
cv::Sobel(src, dx, src.depth(), 1, 0);
cv::Sobel(src, dy, src.depth(), 0, 1);
}
\ No newline at end of file
#pragma once
//
// eyemEdge¡¤±êÍ·
//
#ifndef __EYEM_GENERIC_H
#define __EYEM_GENERIC_H
#include "eyemLib.h"
cv::Mat convert(cv::Mat &src, const int depth);
void spatialGradient(cv::Mat src, cv::Mat &dx, cv::Mat &dy);
#endif/* __EYEM_GENERIC_H */
\ No newline at end of file
#include "eyemLib.h"
int main()
{
//char* filename = "D:\\Matlabͼ\\circle_plate_04.png";
//cv::Mat src = cv::imread(filename, cv::IMREAD_GRAYSCALE);
//EyemImage tpImage;
//tpImage.iHeight = src.rows;
//tpImage.iWidth = src.cols;
//tpImage.ucpImage = src.data;
//EyemRect tpRoi;
//tpRoi.iXs = 0;
//tpRoi.iYs = 0;
//tpRoi.iWidth = src.cols;
//tpRoi.iHeight = src.rows;
//int blobNum;
//IntPtr intptr;
//EyemBinBlob *blobs;
//eyemBinBlob(tpImage, tpRoi, 120, EYEM_BIN_WHITE, 1200, &intptr, &blobs, &blobNum);
////must be dispose
//eyemBinFree(intptr);
return 0;
}
\ No newline at end of file
#pragma once
//
// eyemLib·标头
//
#ifndef __EYEM_LIB_H
#define __EYEM_LIB_H
//#include <map>
//#include <list>
//#include <vector>
//#include <limits>
//#include <float.h>
//#include <fstream>
#include <Windows.h>
#include <opencv.hpp>
#include <opencv2\core\simd_intrinsics.hpp>
#ifndef EYEM_EXPORTS
#define EYEM_EXPORTS __declspec(dllexport)
#endif
/********************************************************************************************/
/* 通用标头 */
/********************************************************************************************/
// 一般定义
#define FUNC_OK 0 // 正常
#define FUNC_NOT_ENOUGH_MEM (-1) // 工作内存不足
#define FUNC_ILLEGAL_ARGUMENT (-2) // 参数不合适
#define FUNC_IMAGE_NOT_EXIST (-3) // 图像不存在
#define FUNC_CANNOT_CALC (-100) // 不可计算
#define FUNC_CANNOT_USE (-999) // 不可用
// 错误代码(矩阵计算)
#define FUNC_DET_EQ_ZERO (-110) // 矩阵表达式为零
#define FUNC_FAILED_EIGEN (-111) // 特征值和特征向量计算失败
#define FUNC_FAILED_SVD (-112) // 奇异值分解计算失败
#define FUNC_FAILED_CHOLESKY (-113) // CHOLESKY分解计算失败
// 错误代码(近似计算)
#define FUNC_FAILED_ROBUST (-130) // 稳健估计失败
#define FUNC_FAILED_ELLIPSE (-131) // 不是椭圆形的
#define FUNC_FAILED_ELLIPSOID (-132) // 不是椭圆体
#define FUNC_FAILED_CONE (-133) // 不是在锥面
// 错误代码(摄像机校准)
#define FUNC_FAILED_HOMOGRAPHY (-150) // 同源矩阵计算失败
#define FUNC_FAILED_CAM_PRM (-151) // 摄像机参数计算失败
#define FUNC_FAILED_BUNDLE_ADJ (-152) // バンドル調整失敗
#define FUNC_FAILED_UNDISTORT (-153) // 失真校正失败
// 常数
#define EPS 1.0e-9 // ε
#define DBL_EPS DBL_EPSILON // ε
#define PI 3.1415926535897932384626433832795 // π
#define PI_DEG 180.0 // π(deg)
#define RAD2DEG (PI_DEG/PI) // rad→deg变换
#define DEG2RAD (PI/PI_DEG) // deg→rad变换
#define TWO_PI (2.0*PI) // 2π
#define PI_BY_2 (PI/2.0) // π/2
#ifndef MIN
#define MIN( a, b ) ( ((a) < (b)) ? (a) : (b) )
#endif
#ifndef MAX
#define MAX( a, b ) ( ((a) > (b)) ? (a) : (b) )
#endif
#ifndef SGN
#define SGN( a ) ( ((a) >= (0)) ? (1) : (-1) )
#endif
#ifndef COMPARE
#define COMPARE( a, b ) ( ((a) > (b)) ? (true) : (false) )
#endif
#define ON 1
#define OFF 0
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
typedef intptr_t IntPtr;
// 图像边界处理
#ifndef __EYEM_BORDER
#define __EYEM_BORDER
enum {
EYEM_BORDER_NONE, // 不执行边界处理
EYEM_BORDER_REPLICATE, // 延长最外周灰度值
EYEM_BORDER_REFLECT, // 镜像(相对于最外边缘对称复制)
EYEM_BORDER_ZERO // 填充零灰度
};
#endif
// 图像信息
typedef struct {
void *vpImage; // 地址
int iWidth; // 图像内存 x 方向大小
int iHeight; // 图像内存 y 方向大小
int iDepth; // 图像位深度
} EyemImage;
// 矩形定义
typedef struct {
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iWidth; // x 方向大小(宽度)
int iHeight; // y 方向大小(高度)
} EyemRect;
typedef struct {
int iXs; // 起始点(左上角) x 坐标
int iYs; // 起始点(左上角) y 坐标
int iXe; // 端点(右下) x 坐标
int iYe; // 端点(右下) y 坐标
} EyemRect2;
///////////////////////////////////////////////////////////////////////////////
// Orthogonal Coordinate System
/////////////////////
// int type
//
typedef struct {
int iX; // X坐标
int iY; // Y坐标
} EyemOcsIXY;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iZ; // Z坐标
} EyemOcsIXYZ;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iQ; // θ
} EyemOcsIXYQ;
typedef struct {
int iX; // X坐标
int iY; // Y坐标
int iR; // 半径
} EyemOcsIXYR; // 用于表示圆
typedef struct {
int iA; // a
int iB; // b
int iC; // c
} EyemOcsIABC; // 用于表示直线(一般形式)
typedef struct {
int iR; // ρ
int iQ; // θ
} EyemOcsIRQ; // 用于表示直线(黑森标准形式)或矢量
typedef struct {
int iX; // X坐标(単位:像素)
int iY; // Y坐标(単位:像素)
int iQ; // 斜率(単位:rad)
int iS; // 刻度
} EyemOcsIXYQS;
/////////////////////
// float type
//
typedef struct {
float fX; // X坐标
float fY; // Y坐标
} EyemOcsFXY;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fZ; // Z坐标
} EyemOcsFXYZ;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fQ; // θ
} EyemOcsFXYQ;
typedef struct {
float fX; // X坐标
float fY; // Y坐标
float fR; // 半径
} EyemOcsFXYR; // 用于表示圆
typedef struct {
float fA; // a
float fB; // b
float fC; // c
} EyemOcsFABC; // 用于表示直线(一般形式)
typedef struct {
float fR; // ρ
float fQ; // θ
} EyemOcsFRQ; // 用于表示直线(黑森标准形式)或矢量
typedef struct {
float fX; // X坐标(単位:像素)
float fY; // Y坐标(単位:像素)
float fQ; // 斜率(単位:rad)
float fS; // 刻度
} EyemOcsFXYQS;
/////////////////////
// double type
//
typedef struct {
double dX; // X坐标
double dY; // Y坐标
} EyemOcsDXY;
typedef struct {
double dX; // X坐标
double dY; // Y坐标
double dZ; // Z坐标
} EyemOcsDXYZ;
typedef struct {
double dX; // X坐标
double dY; // Y坐标
double dQ; // θ
} EyemOcsDXYQ;
typedef struct {
double dX; // 中心的X坐标
double dY; // 中心のY坐标
double dR; // 半径
} EyemOcsDXYR; // 円の表現に使用
typedef struct {
double dA; // a
double dB; // b
double dC; // c
} EyemOcsDABC; // 直線(一般形)の表現に使用
typedef struct {
double dR; // ρ
double dQ; // θ
} EyemOcsDRQ; // 直線(ヘッセの標準形)やベクトルの表現に使用
typedef struct {
double dX; // X座標
double dY; // Y座標
double dQ; // 回転角(単位:rad)
double dS; // スケール
} EyemOcsDXYQS;
typedef struct {
double dA; // a
double dB; // b
double dC; // c
double dD; // d
} EyemOcsDABCD; // 平面(一般形)の表現に使用
typedef struct {
double dXo; // 中心のX座標
double dYo; // 中心のY座標
double dL; // 長軸半径
double dS; // 短軸半径
double dQ; // 長軸の傾き(単位:rad)
} EyemOcsDXYLSQ; // 楕円の表現に使用
typedef struct {
EyemOcsDXYZ tP; // 直線上の1点の座標
EyemOcsDXYZ tV; // 直線の方向ベクトル
} EyemOcsDPV; // 3次元空間内の直線の表現に使用
typedef struct {
EyemOcsDXYZ tC; // 楕円体の中心
EyemOcsDXYZ tR; // 軸の半径(dX:長軸, dY:中軸, dZ:短軸)
double dU; // 長軸のXY平面への射影がX軸となす角(単位:rad)
double dV; // 長軸のXY平面とのなす角(単位:rad)
double dW; // 長軸まわりの回転角(単位:rad)
} EyemOcsDCRUVW; // 楕円体の表現に使用
/********************************************************************************************/
/* 每个特定于源的标头 */
/********************************************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////
// 数学计算实用程序(eyemMath.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
double eyemMathCalcInnerProduct(int, double[], double[]);
void eyemMathCalcOuterProduct(double[], double[], double[]);
int eyemMathCalcAngle(int, double[], double[], double *);
double eyemMathCalcNorm(int, double[]);
double eyemMathCalcArgument(double[]);
int eyemMathNormalization(int, double[]);
int eyemMathStat(int, double[], double *, double *, double *);
double eyemMathMedianI(int, int *);
double eyemMathMedianD(int, double *);
int eyemMathOtsuThreshold1d(int, double[], double *);
double eyemMathAreaTriangle(double, double, double, double, double, double);
double eyemMathSignAreaTriangle(double, double, double, double, double, double);
void eyemMathRotatePoint(double, double, double, double, double, double *, double *);
void eyemMathCreateTransParam(int, double, double, double, double, double *, double *, double *);
void eyemMathTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathInvTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathComposeCoord(double, double, double, double, double, double, double *, double *, double *);
double eyemMathInvMatrixOfSyn3X3(double[][3], double[][3]);
void eyemMathInvCoord(double, double, double, double *, double *, double *);
double eyemMathGetDistFromPointToPoint(double, double, double, double);
double eyemMathGetDistFromPointToLine(double, double, double, double, double);
double eyemMathGetDistAndCrossPointFromPointToLine(double, double, double, double, double, double *, double *);
double eyemMathGetDistFromPointToCircle(double, double, double, double, double, double *, double *);
int eyemMathGetDistFromPointToEllipse(double, double, double, double, double, double, double, double *, double *, double *);
int eyemMathCrossPoint(double, double, double, double, double, double, double *, double *);
void eyemMathTransAbcToRq(double, double, double, double *, double *);
double eyemMathCrossAngle(double, double, double, double, double, double);
int eyemMathGetLineFrom2Points(double, double, double, double, double *, double *, double *);
void eyemMathGetOrthogonalLineFromLineAndPoint(double, double, double, double, double *, double *, double *);
int eyemMathCheckAngle(double, double, double);
double eyemMathAddAngle(int, int, double, double);
double eyemMathPrimeAngle(int, int, double);
double eyemMathExtremumOfQuadraticCurves(double, double, double, double *);
double eyemMathExtremumOfQuadraticSurface(double, double, double, double, double, double, double *, double *);
double eyemMathCrossCorrelation(int, double[], double[]);
int eyemMathAutoCorrelation(int, double[], int, double[]);
double eyemMathNormCorrelation(int, double[], double[]);
int eyemMathNormAutoCorrelation(int, double[], int, double[]);
int eyemMathSearchOf1DWithNormCorrelation(int, double[], int, double[], int *, double *);
int eyemMathQuadraticRoots(double[], double[]);
int eyemMathCubicRoots(double[], double[]);
int eyemMathQuarticRoots(double[], double[]);
double eyemMathHorner(int, double[], double);
void eyemMathTransCoord(double, double, double, double, double, double *, double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 矩阵计算实用程序(eyemMat.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
//EYEM_EXPORTS CvMat *eyemMatMallocMatrix(int iRows, int iCols, void *vpData);
//EYEM_EXPORTS void eyemMatFreeMatrix(CvMat *dpMat);
//EYEM_EXPORTS void eyemMatZero(CvMat *vpA);
//EYEM_EXPORTS void eyemMatCopy(CvMat *vpDst, CvMat *vpSrc);
//EYEM_EXPORTS void eyemMatAdd(CvMat *vpA, CvMat *vpB, CvMat *vpC);
EYEM_EXPORTS void eyemMatSub(int, int, void *, void *, void *);
EYEM_EXPORTS void eyemMatMulScalar(double, int, int, void *, void *);
EYEM_EXPORTS int eyemMatMul(int, int, void *, int, int, void *, void *);
EYEM_EXPORTS int eyemMatGenMul(double, int, int, void *, int, int, void *, double, void *, void *);
EYEM_EXPORTS void eyemMatMulTransposed(int, int, int, void *, void *);
EYEM_EXPORTS int eyemMatMulTransposed2(int, int, int, void *, int, int, void *, void *);
EYEM_EXPORTS void eyemMatTranspose(int, int, void *, void *);
EYEM_EXPORTS double eyemMatTrace(int, void *);
EYEM_EXPORTS int eyemMatInvert(int, void *, void *);
EYEM_EXPORTS int eyemMatSolveLU(int, void *, double[], double[]);
EYEM_EXPORTS int eyemMatSolveSVD(int, int, void *, double[], double[]);
EYEM_EXPORTS int eyemMatJacobiEigen(int, void *, double[], void *);
EYEM_EXPORTS int eyemMatQrEigen(int, void *, double[], void *);
EYEM_EXPORTS int eyemMatSVD(int, int, void *, void *, double[], void *);
EYEM_EXPORTS int eyemMatCholeskyDecomp(int, void *, void *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 近似计算(稳健估计)(eyemFit.cpp)
//
//稳健估计方法
enum
{
EYEM_DIST_USER = -1, /**< User defined distance */
EYEM_DIST_L1 = 1, /**< distance = |x1-x2| + |y1-y2| */
EYEM_DIST_L12 = 2, /**< L1-L2 metric: distance = 2(sqrt(1+x*x/2) - 1)) */
EYEM_DIST_FAIR = 3, /**< distance = c^2(|x|/c-log(1+|x|/c)), c = 1.3998 */
EYEM_DIST_WELSCH = 4, /**< distance = c^2/2(1-exp(-(x/c)^2)), c = 2.9846 */
EYEM_DIST_HUBER = 5, /**< distance = |x|<c ? x^2/2 : c(|x|-c/2), c=1.345 */
EYEM_DIST_TUKEY = 6, /**< distance = di<= c ?(1-(di/c)^2)^2 : 0, c=2.718 di=|yi-(axi+b)|*/
EYEM_DIST_CAUCHY = 7, /**< distance = c^2(|x|/c-log(1+|x|/c)), c = 2.385 */
EYEM_DIST_LOGISTIC = 8, /**< distance w = tanh(r) ./ r c = 1.205*/
EYEM_DIST_ANDREWS = 9, /**< w = (abs(r)<pi) .* sin(r) ./ r c= 1.339*/
EYEM_DIST_ATLWORTH = 10 /**< w = 1 * (abs(r)<1) c=2.975*/
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemFitLine(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, int numToIgnore, EyemOcsDABC &tpLine);
EYEM_EXPORTS int eyemRobustFitLine(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, double dRobustCoef, EyemOcsDABC &tpLine);
EYEM_EXPORTS int eyemFitPlane(int, EyemOcsDXYZ[], int, double, EyemOcsDABCD *);
EYEM_EXPORTS int eyemFitCircle(int iPtnNum, EyemOcsDXY *taPoint, int iCalcMode, int numToIgnore, EyemOcsDXYR &tpCircle);
EYEM_EXPORTS int eyemFitEllipse(int, EyemOcsDXY[], int, double, EyemOcsDXYLSQ *);
EYEM_EXPORTS int eyemFitEllipseC(int, EyemOcsDXY[], int, double, double[]);
EYEM_EXPORTS int eyemFitConics(int, EyemOcsDXY[], int, double, double[]);
EYEM_EXPORTS int eyemFitParabola(int, EyemOcsDXY[], int, double, EyemOcsDABC *);
EYEM_EXPORTS int eyemFitEllipsoid(int, EyemOcsDXYZ[], int, double, EyemOcsDCRUVW *);
EYEM_EXPORTS int eyemFitCone(int, EyemOcsDXYZ[], int, double, double[]);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 二维几何计算(二维卡尺)(eyemClp2d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS void eyemClp2dDistanceTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, double &tpDist);
EYEM_EXPORTS void eyemClp2dCenterTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY &tpCenter);
EYEM_EXPORTS int eyemClp2dLineTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine);
EYEM_EXPORTS int eyemClp2dMidperpendicularTwoPoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDABC &tpLine);
EYEM_EXPORTS int eyemClp2dVerticalLinePointAndLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, EyemOcsDABC &tpVertical);
EYEM_EXPORTS void eyemClp2dLinePointAndSlope(EyemOcsDXY tpPoint, double dSlope, EyemOcsDABC &tpLine);
EYEM_EXPORTS int eyemClp2dIntersectionTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDXY &tpPoint);
EYEM_EXPORTS int eyemClp2dAngleTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, double &dpAngle);
EYEM_EXPORTS int eyemClp2dCenterLineOfTwoLines(EyemOcsDABC tpLine1, EyemOcsDABC tpLine2, EyemOcsDABC &tpLineC);
EYEM_EXPORTS int eyemClp2dDistancePointToLine(EyemOcsDXY tpPoint, EyemOcsDABC tpLine, double &dpDist);
EYEM_EXPORTS int eyemClp2dTranslationOfLine(EyemOcsDABC tpSrcL, EyemOcsDXY tpTrans, EyemOcsDABC &tpDstL);
EYEM_EXPORTS void eyemClp2dAreaTriangle(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, double &dpArea);
EYEM_EXPORTS int eyemClp2dCircleThreePoints(EyemOcsDXY tpPoint1, EyemOcsDXY tpPoint2, EyemOcsDXY tpPoint3, EyemOcsDXYR &tpCircle);
EYEM_EXPORTS int eyemClp2dIntersectionLineAndCircle(EyemOcsDABC tpLine, EyemOcsDXYR tpCircle, EyemOcsDXY &tpPoint1, EyemOcsDXY &tpPoint2);
EYEM_EXPORTS int eyemClp2dTangentPointToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDABC &tpTangent1, EyemOcsDXY &tpContact1, EyemOcsDABC &tpTangent2, EyemOcsDXY &tpContact2);
EYEM_EXPORTS int eyemClp2dClosestToCircle(EyemOcsDXY tpPoint, EyemOcsDXYR tpCircle, EyemOcsDXY &tpClosest, double &dpDist);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 3D 几何计算(3D 卡尺)(eyemClp3d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
void eyemClp3dDistanceTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, double *);
void eyemClp3dCenterTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDXYZ *);
int eyemClp3dLineTwoPoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDPV *);
int eyemClp3dFootOfPerpendicularToLine(EyemOcsDXYZ *, EyemOcsDPV *, EyemOcsDXYZ *);
int eyemClp3dVerticalLinePointAndLine(EyemOcsDXYZ *, EyemOcsDPV *, EyemOcsDPV *);
int eyemClp3dDistancePointToLine(EyemOcsDXYZ *, EyemOcsDPV *, double *);
int eyemClp3dDistanceTwoLines(EyemOcsDPV *, EyemOcsDPV *, double *);
int eyemClp3dPlaneThreePoints(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDABCD *);
int eyemClp3dVerticalPlanePointAndVector(EyemOcsDXYZ *, EyemOcsDXYZ *, EyemOcsDABCD *);
int eyemClp3dVerticalLinePointAndPlane(EyemOcsDXYZ *, EyemOcsDABCD *, EyemOcsDPV *);
int eyemClp3dDistancePointToPlane(EyemOcsDXYZ *, EyemOcsDABCD *, double *);
int eyemClp3dIntersectionLineAndPlane(EyemOcsDPV *, EyemOcsDABCD *, EyemOcsDXYZ *);
int eyemClp3dAngleLineAndPlane(EyemOcsDPV *, EyemOcsDABCD *, double *);
int eyemClp3dFootOfPerpendicularToPlane(EyemOcsDXYZ *, EyemOcsDABCD *, EyemOcsDXYZ *);
int eyemClp3dIntersectionTwoPlanes(EyemOcsDABCD *, EyemOcsDABCD *, EyemOcsDPV *);
int eyemClp3dAngleTwoPlanes(EyemOcsDABCD *, EyemOcsDABCD *, double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 计算几何(eyemCg.cpp)
//
// 线交叉状态
enum {
EYEM_CG_NOT_INTERSECTION, // 未相交
EYEM_CG_INTERSECTION, // 相交(彼此交叉)
};
// 点位置状态
enum {
EYEM_CG_OUTER, // 在外部
EYEM_CG_INNER, // 在内部
EYEM_CG_BORDER // 在边界上
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemCgSortByArgument(int n, EyemOcsDXY taSrcPt[], EyemOcsDXY taDstPt[]);
int eyemCgConvexHull(int, EyemOcsDXY[], int *, EyemOcsDXY[]);
int eyemCgSmallestEnclosingCircle(int, EyemOcsDXY[], EyemOcsDXY *, double *);
int eyemCgIntersectionOfTwoSegments(EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY *, int *, EyemOcsDXY *);
int eyemCgPointInConvexPolygon(int, EyemOcsDXY[], EyemOcsDXY *, int *);
int eyemCgIntersectionLineAndConvexPolygon(int, EyemOcsDXY[], EyemOcsDABC *, EyemOcsDXY[]);
int eyemCgIntersectionSegmentAndConvexPolygon(int, EyemOcsDXY[], EyemOcsDXY *, EyemOcsDXY *, EyemOcsDXY[]);
int eyemCgPointInPolygon(int, EyemOcsDXY[], EyemOcsDXY *, int *);
int eyemCgAreaOfPolygon(int, EyemOcsDXY[], double *);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 2 值 blob 分析(eyemBin.cpp)
//
enum {
EYEM_BIN_BLACK, // 黒
EYEM_BIN_WHITE // 白
};
//全局阈值2值化方法
enum {
HUANG,
ISODATA,
LI,
MAXENTROPY,
MEAN,
MOMENTS,
OTSU,
PERCENTILE,
RENYIENTROPY,
SHANBHAG,
TRIANGLE,
YEN
};
//动态阈值2值化方法
enum {
LIGHT,
DARK,
EQUAL,
NOT_EQUAL
};
// 局部阈值2值化方法
enum
{
BINARIZATION_NIBLACK,
BINARIZATION_WOLF,
BINARIZATION_NICK,
BINARIZATION_SAUVOLA
};
// Chain code:
// 7 0 1
// 6 2
// 5 4 3
#define CV_CHAINCODE_UP 0 ///< Up.
#define CV_CHAINCODE_UP_RIGHT 1 ///< Up and right.
#define CV_CHAINCODE_RIGHT 2 ///< Right.
#define CV_CHAINCODE_DOWN_RIGHT 3 ///< Down and right.
#define CV_CHAINCODE_DOWN 4 ///< Down.
#define CV_CHAINCODE_DOWN_LEFT 5 ///< Down and left.
#define CV_CHAINCODE_LEFT 6 ///< Left.
#define CV_CHAINCODE_UP_LEFT 7 ///< Up and left.
const char movesE[4][3][4] = { { { -1, -1, 3, CV_CHAINCODE_UP_LEFT },{ 0, -1, 0, CV_CHAINCODE_UP },{ 1, -1, 0, CV_CHAINCODE_UP_RIGHT } },
{ { 1, -1, 0, CV_CHAINCODE_UP_RIGHT },{ 1, 0, 1, CV_CHAINCODE_RIGHT },{ 1, 1, 1, CV_CHAINCODE_DOWN_RIGHT } },
{ { 1, 1, 1, CV_CHAINCODE_DOWN_RIGHT },{ 0, 1, 2, CV_CHAINCODE_DOWN },{ -1, 1, 2, CV_CHAINCODE_DOWN_LEFT } },
{ { -1, 1, 2, CV_CHAINCODE_DOWN_LEFT },{ -1, 0, 3, CV_CHAINCODE_LEFT },{ -1, -1, 3, CV_CHAINCODE_UP_LEFT } }
};
const char movesI[4][3][4] = { { { 1, -1, 3, CV_CHAINCODE_UP_RIGHT },{ 0, -1, 0, CV_CHAINCODE_UP },{ -1, -1, 0, CV_CHAINCODE_UP_LEFT } },
{ { -1, -1, 0, CV_CHAINCODE_UP_LEFT },{ -1, 0, 1, CV_CHAINCODE_LEFT },{ -1, 1, 1, CV_CHAINCODE_DOWN_LEFT } },
{ { -1, 1, 1, CV_CHAINCODE_DOWN_LEFT },{ 0, 1, 2, CV_CHAINCODE_DOWN },{ 1, 1, 2, CV_CHAINCODE_DOWN_RIGHT } },
{ { 1, 1, 2, CV_CHAINCODE_DOWN_RIGHT },{ 1, 0, 3, CV_CHAINCODE_RIGHT },{ 1, -1, 3, CV_CHAINCODE_UP_RIGHT } }
};
// Blob 分析结果
typedef struct {
int iArea; // 面积
double dCenterX; // 重心x坐标
double dCenterY; // 重心y坐标
int iXs, iYs, iXe, iYe; // 外接矩形(始点,终点)
int iWidth, iHeight; // 外接矩形(x 方向大小(宽度),y 方向大小(高度))
double dTheta; // 主轴倾斜角(rad)
} EyemBinBlob;
typedef struct {
int iLabel; // 标签
double dX; // x坐标
double dY; // y坐标
double dVx, dVy; // 向量
} EyemChainCode;
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemBinThreshold(EyemImage tpSrcImg, int iLightDark, double dThresh, double dMaxVal, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinAutoThreshold(EyemImage tpSrcImg, double dSigma, int iLightDark, int binMethod, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinNiBlack(EyemImage tpSrcImg, EyemImage *tpDstImg, int iType, int iWinSize, double dK, int binarizationMethod, double dR);
EYEM_EXPORTS int eyemBinDynThreshold(EyemImage tpSrcImg, EyemImage tpThresholdImg, int iOffset, int iLightDark, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinDilation(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinErosion(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinOpening(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemBinClosing(EyemImage tpSrcImg, int iBinLevel, int iNum, EyemImage *tpDstImg);
EYEM_EXPORTS bool eyemBinFree(IntPtr hObject);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 一维边缘提取(eyemEdge1d.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemEdge1dGenMeasureRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, const char *ccSubType, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject);
EYEM_EXPORTS int eyemEdge1dGenPosRect(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, double dSigma, double dAmpThresh, IntPtr *hObject);
EYEM_EXPORTS int eyemEdge1dFitLine(IntPtr hObject, int iClippingEndPoints, int iMaxIterations, double dRobustCoef, EyemOcsDABC *tpLine);
EYEM_EXPORTS int eyemEdge1dFitCircle(IntPtr hObject, int iClippingEndPoints, int iMaxIterations, double dRobustCoef, EyemOcsDXYR *tpCircle);
EYEM_EXPORTS int eyemEdge1dFindLine(EyemImage tpImage, EyemOcsDXY tpLineSt, EyemOcsDXY tpLineEd, int iWhRoi, int iTransition, IntPtr *hObject);
EYEM_EXPORTS bool eyemEdge1dGenMeasureFree(IntPtr hObject);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 二维边缘提取(eyemEdge.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemEdgesPixel(EyemImage tpImage, double dThresh);
EYEM_EXPORTS int eyemEdgesSubpixel(EyemImage tpImage, IntPtr *hObject, EyemOcsDXY **tpEdges, int iFilter, int iLow, int iHigh);
EYEM_EXPORTS int eyemSkeleton(EyemImage tpImage, cv::Mat &skeleton);
EYEM_EXPORTS int eyemSobelAmp(EyemImage tpImage, EyemImage &ImaAmp);
EYEM_EXPORTS int eyemAutoCanny(EyemImage tpImage, float dSigma = 0.33);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 点云匹配(eyemMatch.cpp)
//
// 处理类型
enum {
EYEM_MATCH_LSQ, // 最小二乗法
EYEM_MATCH_LSQ_S, // 加权最小二乗法
EYEM_MATCH_ROBUST, // 稳健估计・无比例估计
EYEM_MATCH_ROBUST_S, // 稳健估计・带比例估计
EYEM_MATCH_MINMAX, // MINMAX方法・无比例估计
EYEM_MATCH_MINMAX_S // MINMAX方法・带比例估计
};
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemMatchBasic(int, EyemOcsDXY[], EyemOcsDXY[], EyemOcsDXYQ *, int, double, EyemOcsDXYQS *);
int eyemMatchDelta(EyemOcsDXYQ *, EyemOcsDXYQS *, double *, double *, double *, double *);
int eyemMatchPoints(int, EyemOcsDXY[], EyemOcsDXY[], EyemOcsDXYQ *, EyemOcsDXYQS *, EyemOcsDXY[], double[]);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 摄像机校准(eyemCalib.cpp)
//
// 模式数据
typedef struct {
int iPtnRefN; // 图案参考点数
EyemOcsDXY *tpObjPt; // 阵列参考点的实际坐标(単位:mm)
EyemOcsDXY *tpImgPt; // 图案参考点的图像坐标(単位:像素)
} EyemCalibPtn;
// 同源矩阵
typedef struct {
double daH[3][3]; // 同源矩阵 H
double daInvH[3][3]; // 矩阵 H 的逆矩阵
} EyemCalibHom;
// 摄像机的内参数(intrinsic parameter)
typedef struct {
double daA[3][3]; // 内参数矩阵
double dK1, dK2; // 径向失真系数
double dK3, dK4, dK5; // 径向失真系数
double daInvA[3][3]; // 内参数矩阵的逆矩阵
} EyemCalibInt;
// 摄像机外部参数(extrinsic parameter)
typedef struct {
double daR[3][3]; // 旋转矩阵
double daT[3]; // 平移矢量
double daRdr[3]; // 旋转矢量(罗德里格斯表示)
} EyemCalibExt;
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
int eyemCalibCameraCalibrate(int, EyemCalibPtn[], double, EyemCalibInt *, EyemCalibExt[], double *, int);
int eyemCalibCalcHomography(int, void *, void *, double, void *);
int eyemCalibRodrigues(int, double[3], double[3][3]);
int eyemCalibUnDistortPoint(EyemCalibInt *, double, double, double *, double *);
int eyemCalibUnDistortMat(EyemCalibInt *, double, double, double *, double *);
int eyemCalibChange3Dto2D(EyemOcsDXYZ *, EyemCalibInt *, EyemCalibExt *, EyemOcsDXY *, int);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像平滑滤镜(eyemSmooth.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemSmoothMean(EyemImage tpImage, int kSizew, int kSizeh, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemSmoothGaussian(EyemImage tpImage, int kSizew, int kSizeh, double dSigmaX, double dSigmaY, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemSmoothMedian(EyemImage tpImage, int kSize, EyemImage *tpDstImg);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 图像线段检测器(eyemEDLinesDetector.cpp)
//
#ifdef __cplusplus
extern "C" {
#endif
// 函数接口
EYEM_EXPORTS int eyemEDLinesDetector(EyemImage tpImage, int _gradThresh, int _anchorThresh, int _scanInterval, int _minPathLen, double _sigma, bool _sumFlag, double _line_error, int _min_line_len, double _max_distance_between_two_lines, double _max_error, EyemImage *tpDstImg);
#ifdef __cplusplus
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// 其他工具(eyemMisc.cpp)
//
// 条码 解码结果
typedef struct {
double dAngle; // 角度
int iCenterX; // y坐标
int iCenterY; // y坐标
LPSTR lpszType; // 码类型
LPSTR lpszText; // 码内容
} EyemBarCode;
#ifdef __cplusplus
extern "C" {
#endif
EYEM_EXPORTS int eyemDetectAndDecode(EyemImage tpImage, EyemRect tpRoi, const char *ccFileName, const char *ccCodeType, IntPtr *hObject, EyemBarCode **tpResult, int *ipNum, bool bUseNiBlack, int iBlockSize, const int iRangeC, int iSymbolMin, int iSymbolMax, double dScaleUpAndDown = 0.5, double dToleErr = 0.5, double dMinorStep = 1.0);
EYEM_EXPORTS bool eyemDetectAndDecodeFree(IntPtr hObject);
EYEM_EXPORTS int eyemCountObject(EyemImage tpImage, const char *fileName, double dOffset, int iMinArea, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemCountObjectIrregularParts(EyemImage tpImage, const char *fileName, double dOffset, const char * ccSubType, int iMaxArea, int iWinSize, LPSTR *lpszNumObj, EyemImage *tpDstImg);
EYEM_EXPORTS int eyemImageRead(const char *filename, int iFalgs, EyemImage *ucpImage);
EYEM_EXPORTS int eyemImageReadRaw(const char *filename, int iWidth, int iHeight, int iDepth, EyemImage *tpImage);
EYEM_EXPORTS void eyemImageFree(void *ipImage);
#ifdef __cplusplus
}
#endif
#endif/* __EYEM_LIB_H */
此文件类型无法预览
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{33D5F550-C799-4B05-8E14-ACA390DF5442}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>eyemLib</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>D:\opencv420\build\include;D:\opencv420\build\include\opencv2;D:\zxing-cpp-master\core\src;D:\zxing-cpp-master\opencv\src;$(IncludePath)</IncludePath>
<LibraryPath>D:\opencv420\build\x64\vc14\lib;D:\zxing-cpp-master\build\Debug;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>D:\opencv420\build\include;D:\opencv420\build\include\opencv2;D:\zxing-cpp-master\core\src;D:\zxing-cpp-master\opencv\src;$(IncludePath)</IncludePath>
<LibraryPath>D:\opencv420\build\x64\vc14\lib;D:\zxing-cpp-master\build\Release;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;HYCOMMONWINAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WholeProgramOptimization>false</WholeProgramOptimization>
<MultiProcessorCompilation>false</MultiProcessorCompilation>
<OpenMPSupport>true</OpenMPSupport>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libzxing-debug.lib;libdmtx.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<OpenMPSupport>true</OpenMPSupport>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libdmtx.lib;libzxing.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="eyemBarCode.h" />
<ClInclude Include="eyemBin.h" />
<ClInclude Include="eyemCalib.h" />
<ClInclude Include="eyemClp2d.h" />
<ClInclude Include="eyemEdge.h" />
<ClInclude Include="eyemEdge1d.h" />
<ClInclude Include="eyemEDLinesDetector.h" />
<ClInclude Include="eyemFit.h" />
<ClInclude Include="eyemGeneric.h" />
<ClInclude Include="eyemLib.h" />
<ClInclude Include="eyemMat.h" />
<ClInclude Include="eyemMath.h" />
<ClInclude Include="eyemMisc.h" />
<ClInclude Include="eyemSmooth.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="eyemBarCode.cpp" />
<ClCompile Include="eyemBin.cpp" />
<ClCompile Include="eyemCalib.cpp" />
<ClCompile Include="eyemCg.cpp" />
<ClCompile Include="eyemClp2d.cpp" />
<ClCompile Include="eyemClp3d.cpp" />
<ClCompile Include="eyemEdge.cpp" />
<ClCompile Include="eyemEdge1d.cpp" />
<ClCompile Include="eyemEDLinesDetector.cpp" />
<ClCompile Include="eyemFit.cpp" />
<ClCompile Include="eyemGeneric.cpp" />
<ClCompile Include="eyemLib.cpp" />
<ClCompile Include="eyemMat.cpp" />
<ClCompile Include="eyemMatch.cpp" />
<ClCompile Include="eyemMath.cpp" />
<ClCompile Include="eyemMisc.cpp" />
<ClCompile Include="eyemSmooth.cpp" />
<ClCompile Include="libopencv.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="eyemLib.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="eyemLib.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="eyemBin.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemEdge1d.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemFit.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemMisc.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemClp2d.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemMat.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemCalib.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="eyemMath.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemSmooth.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemEdge.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemGeneric.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemBarCode.h">
<Filter>源文件</Filter>
</ClInclude>
<ClInclude Include="eyemEDLinesDetector.h">
<Filter>源文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="eyemLib.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="libopencv.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemMath.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemFit.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemClp2d.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemClp3d.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemCg.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemBin.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemEdge1d.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemMatch.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemCalib.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemSmooth.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemMisc.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemMat.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemEdge.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemGeneric.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemBarCode.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="eyemEDLinesDetector.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="eyemLib.rc">
<Filter>资源文件</Filter>
</ResourceCompile>
</ItemGroup>
</Project>
\ No newline at end of file
#include "eyemMat.h"
//CvMat *eyemMatMallocMatrix(int iRows, int iCols, void *vpData)
//{
// CvMat *dpMat = cvCreateMat(iRows, iCols, CV_64F);
// cvInitMatHeader(dpMat, iRows, iCols, CV_64F, vpData);
// return dpMat;
//}
//
//void eyemMatFreeMatrix(CvMat *dpMat)
//{
// cvReleaseMat(&dpMat);
//}
//
//void eyemMatZero(CvMat *dpMat)
//{
// cvSetZero(dpMat);
//}
//
//void eyemMatCopy(CvMat *vpDst, CvMat *vpSrc)
//{
// vpDst = cvCloneMat(vpSrc);
//}
//
//void eyemMatAdd(CvMat *vpA, CvMat *vpB, CvMat *vpC)
//{
// cvAdd(vpA, vpB, vpC);
//}
\ No newline at end of file
#pragma once
//
// eyemMatͷ
//
#ifndef __EYEM_MAT_H
#define __EYEM_MAT_H
#include "eyemLib.h"
#endif/* __EYEM_MAT_H */
文件属性发生变化
#include "eyemMath.h"
double eyemMathCalcInnerProduct(int, double[], double[]);
void eyemMathCalcOuterProduct(double[], double[], double[]);
int eyemMathCalcAngle(int, double[], double[], double *);
double eyemMathCalcNorm(int, double[]);
double eyemMathCalcArgument(double[]);
int eyemMathNormalization(int, double[]);
int eyemMathStat(int, double[], double *, double *, double *);
double eyemMathMedianI(int, int *);
double eyemMathMedianD(int, double *);
int eyemMathOtsuThreshold1d(int, double[], double *);
double eyemMathAreaTriangle(double, double, double, double, double, double);
double eyemMathSignAreaTriangle(double, double, double, double, double, double);
void eyemMathRotatePoint(double, double, double, double, double, double *, double *);
void eyemMathCreateTransParam(int, double, double, double, double, double *, double *, double *);
void eyemMathTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathInvTransCoordOfPoint(double, double, double, double, double, double *, double *);
void eyemMathComposeCoord(double, double, double, double, double, double, double *, double *, double *);
double eyemMathInvMatrixOfSyn3X3(double[][3], double[][3]);
void eyemMathInvCoord(double, double, double, double *, double *, double *);
double eyemMathGetDistFromPointToPoint(double, double, double, double);
double eyemMathGetDistFromPointToLine(double, double, double, double, double);
double eyemMathGetDistAndCrossPointFromPointToLine(double, double, double, double, double, double *, double *);
double eyemMathGetDistFromPointToCircle(double, double, double, double, double, double *, double *);
int eyemMathGetDistFromPointToEllipse(double, double, double, double, double, double, double, double *, double *, double *);
int eyemMathCrossPoint(double, double, double, double, double, double, double *, double *);
void eyemMathTransAbcToRq(double, double, double, double *, double *);
double eyemMathCrossAngle(double, double, double, double, double, double);
int eyemMathGetLineFrom2Points(double, double, double, double, double *, double *, double *);
void eyemMathGetOrthogonalLineFromLineAndPoint(double, double, double, double, double *, double *, double *);
int eyemMathCheckAngle(double, double, double);
double eyemMathAddAngle(int, int, double, double);
double eyemMathPrimeAngle(int, int, double);
double eyemMathExtremumOfQuadraticCurves(double, double, double, double *);
double eyemMathExtremumOfQuadraticSurface(double, double, double, double, double, double, double *, double *);
double eyemMathCrossCorrelation(int, double[], double[]);
int eyemMathAutoCorrelation(int, double[], int, double[]);
double eyemMathNormCorrelation(int, double[], double[]);
int eyemMathNormAutoCorrelation(int, double[], int, double[]);
int eyemMathSearchOf1DWithNormCorrelation(int, double[], int, double[], int *, double *);
int eyemMathQuadraticRoots(double[], double[]);
int eyemMathCubicRoots(double[], double[]);
int eyemMathQuarticRoots(double[], double[]);
double eyemMathHorner(int, double[], double);
void eyemMathTransCoord(double, double, double, double, double, double *, double *);
\ No newline at end of file
#pragma once
//
// eyemMathͷ
//
#ifndef __EYEM_MATH_H
#define __EYEM_MATH_H
#include "eyemLib.h"
#endif/* __EYEM_MATH_H */
此文件的差异太大,无法显示。
#pragma once
//
// eyemMiscͷ
//
#ifndef __EYEM_MISC_H
#define __EYEM_MISC_H
#include <omp.h>
#include <io.h>
#include <direct.h>
#include "eyemLib.h"
constexpr double c = PI / 180.;
#endif/* __EYEM_MISC_H */
#include "eyemSmooth.h"
int eyemSmoothMean(EyemImage tpImage, int kSizew, int kSizeh, EyemImage *tpDstImg)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat dstImage;
cv::blur(image, dstImage, cv::Size(kSizew, kSizeh));
return FUNC_OK;
}
int eyemSmoothGaussian(EyemImage tpImage, int kSizew, int kSizeh, double dSigmaX, double dSigmaY, EyemImage *tpDstImg)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat dstImage;
cv::GaussianBlur(image, dstImage, cv::Size(kSizew, kSizeh), dSigmaX, dSigmaY);
return FUNC_OK;
}
int eyemSmoothMedian(EyemImage tpImage, int kSize, EyemImage *tpDstImg)
{
cv::Mat image(tpImage.iHeight, tpImage.iWidth, CV_8UC1, tpImage.vpImage);
if (image.empty()) {
return FUNC_IMAGE_NOT_EXIST;
}
cv::Mat dstImage;
cv::medianBlur(image, dstImage, kSize);
return FUNC_OK;
}
\ No newline at end of file
#pragma once
//
// eyemSmoothͷ
//
#ifndef __EYEM_SMOOTH_H
#define __EYEM_SMOOTH_H
#include "eyemLib.h"
#endif/* __EYEM_SMOOTH_H */
\ No newline at end of file
此文件类型无法预览
#ifdef _DEBUG
//#pragma comment( lib, "IlmImfd.lib" )
//#pragma comment( lib, "ippicvmt.lib" )
//#pragma comment( lib, "ippiwd.lib" )
//#pragma comment( lib, "ittnotifyd.lib" )
//#pragma comment( lib, "libjasperd.lib" )
//#pragma comment( lib, "libjpeg-turbod.lib" )
//#pragma comment( lib, "libpngd.lib" )
//#pragma comment( lib, "libprotobufd.lib" )
//#pragma comment( lib, "libtiffd.lib" )
//#pragma comment( lib, "libwebpd.lib" )
//#pragma comment( lib, "quircd.lib" )
//#pragma comment( lib, "zlibd.lib" )
#pragma comment( lib, "opencv_world420d.lib" )
#else
//#pragma comment( lib, "IlmImf.lib" )
//#pragma comment( lib, "ippicvmt.lib" )
//#pragma comment( lib, "ippiw.lib" )
//#pragma comment( lib, "ittnotify.lib" )
//#pragma comment( lib, "libjasper.lib" )
//#pragma comment( lib, "libjpeg-turbo.lib" )
//#pragma comment( lib, "libpng.lib" )
//#pragma comment( lib, "libprotobuf.lib" )
//#pragma comment( lib, "libtiff.lib" )
//#pragma comment( lib, "libwebp.lib" )
//#pragma comment( lib, "quirc.lib" )
//#pragma comment( lib, "zlib.lib" )
#pragma comment( lib, "opencv_world420.lib" )
#endif
此文件类型无法预览
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by eyemLib.rc
// ¶һĬֵ
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!