DetectCodePoint.h
#ifndef DetectCodedPoint_H
#define DetectCodedPoint_H
#include "cv.h"
#include "highgui.h"
#include <vector>
#include <atlstr.h>
#include <stdio.h>
#include <string.h>
using namespace std;
using namespace cv;
//****************************************
//定义一用于存储可能的编码信息,包括中心点坐标\椭圆率\椭圆的半长轴
struct strEllipseInfo
{
CvPoint2D32f p; //椭圆中心坐标
float height; //椭圆的长轴
float width; //椭圆的短轴
float angle; //椭圆的倾斜角
float Celiipse; //椭圆的圆度值
float area; //椭圆的面积
float perimeter; //椭圆的周长
double pointErr; //拟合椭圆时形成的点距误差
strEllipseInfo()
{
p = cvPoint2D32f(0.0,0.0);
height = 0.0;
width = 0.0;
angle = 0.0;
Celiipse = 0.0;
area = 0.0;
perimeter = 0.0;
pointErr = 0.0;
}
strEllipseInfo(CvPoint2D32f point ,float in_height,float in_width,float in_angle,
float in_Celiipse,float in_area, float in_perimeter, double in_pointErr)
{
p = point;
height = in_height;
width = in_width;
angle = in_angle;
Celiipse = in_Celiipse;
area = in_area;
perimeter = in_perimeter;
pointErr = in_pointErr;
}
};
//*****************************************************
struct tagPoint
{
CvPoint2D32f point;
int pointgray;
};
//**************************************************************
//**************************************************************
//输出的标记点信息
struct tagCodeInfo
{
double fx;//中心坐标x
double fy;//中心坐标y;
int icodeNumber;//标记圆码值,非零代表编码点的编码值,0代表非编码点
};
class DetectCodePoint
{
public:
DetectCodePoint (int thresh);
//~DetectCodePoint();
void MatrixFromImageGroup(vector<CString>& fileNameList,CString path);
vector<tagCodeInfo> DetectReferencePointFromImage(CString fileName,CString jieguoname, CString original);
IplImage* ImagLoad( CString filename );
private:
int edge_thresh ; //canny边缘检测的一个参数,另一个参数是其3倍
vector<double> areaError;
//**********
//内部操作 *
//**********
protected:
double Pointangle( CvPoint2D32f pt1, CvPoint2D32f pt2, CvPoint2D32f pt0 );
void DetectCodePoint::GrayImage(IplImage* source,IplImage* dest);
IplImage* SmothImage(IplImage* grayimage);
IplImage* HistImage(IplImage* Gsmothimage);
IplImage* EdgeImage(IplImage* Hist_Image,int edge_thresh);
int otsu (IplImage *image,int x0, int y0, int dx, int dy);
void DetectCodePoint::TwoGrayPlatm( IplImage* gray,IplImage* imageplat);
vector<strEllipseInfo> process_image(IplImage *edgeimage,IplImage* twogray );
vector<strEllipseInfo> RemoveFalRefPt(vector<strEllipseInfo>& vector1 ); //去掉不是标记点的
void departUncode_AND_Code(vector<strEllipseInfo>& vCdatRefPt,
vector<strEllipseInfo>& vCodePt,
vector<strEllipseInfo>& vUncodePt,
IplImage* twogray);
unsigned short incoded(strEllipseInfo codebox,IplImage* image, double beishu);
int min_of_shift(unsigned short codenumber);
void TwoGray(IplImage* gray,IplImage* imageplat,IplImage* twogray);
void ShowNumber(IplImage* image,CvPoint point,int number);
int GetEdgeThresh(){return edge_thresh;}
bool CheckWhiteCounter(CvSeq* cont,IplImage *twogray);
unsigned short Rol(unsigned short a);
void DrawRedCross(CvPoint pt,IplImage* image);
void Sort (int* pData,int Count);
int averGrayofCount(CvSeq* cont,IplImage *twogray,CvPoint center,int radius);
CvBox2D32f* FitEllipse(CvSeq* cont);
int threshEllispe(IplImage* gray ,strEllipseInfo codepoint);
float threshcirque(IplImage* gray,strEllipseInfo point1); //求指定图象上一个连同域内象素点个数的总和
};
#endif
DetectCodePoint.cpp
#include "DetectCodedPoint.h"
#include <math.h>
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std ;
using namespace cv;
#ifndef _EiC
#include "cv.h"
#include "highgui.h"
#endif
#define HDIM 256 //灰度直方图的数组大小
const double PI = (atan(1.0)*4);
const double dseta=PI/180.0;
#define arraysize 360;//解码的单位圆的数组大小
/*********************************************
*函数名称:Rol
*函数功能:实现将unsigned short b进行循环左移1位
*返回类型:循环移位后的结果
*最后修改:2017年9月30日 张逸骅
***********************************************/
unsigned short DetectCodePoint::Rol(unsigned short a)
{
unsigned short b;
b=(a<<1)|(a>>15);
return b;
}
/******************************************************
*DetectCodePoint类构造函数
*******************************************************/
DetectCodePoint::DetectCodePoint(int h)
{
edge_thresh=h;
}
/*******************************************
*函数名称:ImagLoad
*功能: 读取图片
*返回值: 待测图片
**********************************************/
IplImage* DetectCodePoint::ImagLoad( CString filename)
{
IplImage* image=0;
image=cvLoadImage(filename,-1);//LOAD image
return image;
}
/*******************************************************************
* 函数名称:IplImage* GrayImage()
* 函数功能:把任意格式的图形转换成单通道的灰度图
* 输入参数:IplImage* source --指向圆图形
* 输出参数:IplImage* gray --指向转换后的灰度图,必须为8位单通道
* 最后修改:2017年9月30日 张逸骅
********************************************************************/
void DetectCodePoint::GrayImage(IplImage* source,IplImage* dest)
{
cvCvtColor(source, dest, CV_BGR2GRAY);
}
/*******************************************************************
* 函数名称:IplImage* TwoGrayPlatm()
* 函数功能:求取灰度图像上每个像素二值化的灰度阈值
使用的块的大小为编码标记圆在图象上的大致像素大小160*160
* 输入参数:IplImage* gray --指向灰度图
* 输出参数:IplImage* --阈值模板
* 最后修改:2017年9月30日 张逸骅
********************************************************************/
void DetectCodePoint::TwoGrayPlatm( IplImage* pSrcImage,IplImage* pDstImage)
{
int blockSize=200;
IplImage* pThrImage=cvCreateImage(cvSize(pSrcImage->width/blockSize,pSrcImage->height/blockSize),pSrcImage->depth,1);
cvZero(pThrImage);
int dx,dy;
int nThrData=0;
int i=0;
int j=0;
for (i=0;i<pThrImage->height;i++)
{
for (j=0;j<pThrImage->width;j++)
{
if ((j+2)*blockSize>pSrcImage->width)
{
dx=pSrcImage->width-j*blockSize;
}
else
{
dx=2*blockSize;
}
if ((i+2)*blockSize>pSrcImage->height)
{
dy=pSrcImage->height-i*blockSize;
}
else
{
dy=2*blockSize;
}
int nThrData=otsu(pSrcImage,j*blockSize,i*blockSize,dx,dy);
((uchar*)(pThrImage->imageData+i*pThrImage->widthStep))[j]=nThrData;
}
}
cvResize(pThrImage,pDstImage,CV_INTER_LINEAR);
cvReleaseImage(&pThrImage);
}
/*************************************************************
*函数名称:TwoGray()
*函数功能:二值化灰度图
*输入参数:原始灰度图指针
*输出参数二值化后的图象指针
*最后修改:2017年9月30日 张逸骅
*****************************************************************/
void DetectCodePoint::TwoGray(IplImage* gray,IplImage* imageplat,IplImage* twogray)
{
// IplImage* twogray=cvCreateImage(cvSize(gray->width,gray->height), IPL_DEPTH_8U, 1);
cvZero(twogray);
int width=gray->width;
int height=gray->height;
int widthstep1=gray->widthStep;
int widthstep2=imageplat->widthStep;
int widthstep3=twogray->widthStep;
uchar* resout_data=(unsigned char*)(twogray->imageData);
uchar* graydata= (unsigned char*)(gray->imageData);
uchar* platdata= (unsigned char*)(imageplat->imageData);
for (int j=0;j<height;j++)
{
for (int i=0;i<width;i++)
{
int gray=((uchar*)(graydata+j*widthstep1))[i];
int throsh=((uchar*)(platdata+j*widthstep2))[i];
if (gray>throsh)
{
((uchar*)(resout_data+j*widthstep3))[i]=255;
}
}
}
}
/***********************************************************
*函数名称: SmothImage();
*函数功能:平滑滤波
*输入参数:IplImage* grayimage ----进行平滑滤波的原始图象指针
*输出参数:IplImage* smothimage----滤波后的图形指针
*最后修改:2017年9月30日 张逸骅
*********************************************************/
IplImage* DetectCodePoint::SmothImage(IplImage* grayimage )
{
IplImage* smothimage=cvCreateImage(cvSize(grayimage->width,grayimage->height), IPL_DEPTH_8U, 1);
cvSmooth( grayimage , smothimage, CV_BLUR, 3, 3, 0, 0 );
return smothimage;
}
/**********************************************************
*函数名称:HistImage(IplImage* Gsmothimage,IplImage* histimage);
*功能:求输入图形的直方图均衡化图形
*输入参数:指向平滑后灰度图
*输出参数:直方图均衡化后的图象指针
*最后修改:2017年9月30日 张逸骅
************************************************************/
IplImage* DetectCodePoint::HistImage(IplImage* smothimage)
{
IplImage* histimage= cvCreateImage(cvSize(smothimage->width,smothimage->height), IPL_DEPTH_8U, 1);
CvHistogram *hist = 0;
int n = HDIM;
double nn[HDIM];
uchar T[HDIM];
CvMat *T_mat;
int x;
int sum = 0; // sum of pixels of the source image 图像中象素点的总和
double val = 0;
// calculate histgram 计算直方图
hist = cvCreateHist( 1, &n, CV_HIST_ARRAY, 0, 1 );
cvCalcHist( &smothimage, hist, 0, 0 );
// Create Accumulative Distribute Function of histgram
val = 0;
for ( x = 0; x < n; x++)
{
val = val + cvGetReal1D (hist->bins, x);
nn[x] = val;
}
// Compute intensity transformation 计算变换函数的离散形式
sum = smothimage->height * smothimage->width;
for( x = 0; x < n; x++ )
{
T[x] = (uchar) (255 * nn[x] / sum); // range is [0,255]
}
// Do intensity transform for source image
histimage = cvCloneImage( smothimage );
T_mat = cvCreateMatHeader( 1, 256, CV_8UC1 );
cvSetData( T_mat, T, 0 );
// directly use look-up-table function 直接调用内部函数完成 look-up-table 的过程
cvLUT( smothimage, histimage, T_mat );
return histimage;
}
/********************************************************************
*函数名称EdgeImage()
*功能:采用Canny算子对输入图象进行边缘检测
*输入参数:IplImage* Hist_Image
*输出参数:IplImage* edgeimage
*最后修改:2017年9月30日 张逸骅
********************************************************************/
IplImage* DetectCodePoint::EdgeImage(IplImage* Hist_Image,int edge_thresh)
{
IplImage* edgeimage=cvCreateImage(cvSize(Hist_Image->width,Hist_Image->height), IPL_D