382 lines
8.9 KiB
C++
382 lines
8.9 KiB
C++
#include "StdAfx.h"
|
|
#include "AutoCrop.h"
|
|
#ifndef _USE_MATH_DEFINES
|
|
#define _USE_MATH_DEFINES
|
|
#endif // !_USE_MATH_DEFINES
|
|
#include <math.h>
|
|
#include "PublicFunc.h"
|
|
|
|
CAutoCrop::CAutoCrop( bool bFill,bool bautoDeScrew, bool bCrop,SIZE dstsize,SIZE originSize)
|
|
:m_bAutoDescrew(bautoDeScrew), m_bCrop(bCrop), m_bFill(bFill),m_dstSize(dstsize),m_originSize(originSize)
|
|
{
|
|
}
|
|
|
|
|
|
CAutoCrop::~CAutoCrop()
|
|
{
|
|
}
|
|
|
|
void CAutoCrop::apply(cv::Mat & dib,int side)
|
|
{
|
|
//XdPrint("CAutoCrop");
|
|
RotatedRect rect;
|
|
vector<Point> contour;
|
|
double scale = 0.25;
|
|
double thresh = 70;
|
|
int blobSize = 200;
|
|
int edgeWidth =5;
|
|
ProcessRect(dib, rect, contour, scale, thresh, blobSize);
|
|
//XdPrint("Begin m_bFill \n");
|
|
if (m_bFill)
|
|
{
|
|
fillBlack(dib, contour,edgeWidth);
|
|
//XdPrint("m_bFill \n");
|
|
}
|
|
|
|
if (m_bAutoDescrew)//自动纠偏
|
|
{
|
|
//XdPrint("m_bAutoDescrew strart\n");
|
|
RotateImage(dib,rect,m_bCrop,m_bFill);//自动纠偏和自动裁切或自动纠偏 不自动裁切
|
|
//XdPrint("m_bAutoDescrew end\n");
|
|
}
|
|
|
|
if (m_bCrop&&!m_bAutoDescrew)//自动裁切 但不纠偏
|
|
{
|
|
vector<Point> vec(contour);
|
|
Rect rectOut=boundingRect(vec);
|
|
Mat temp=dib(rectOut);
|
|
dib=temp.clone();
|
|
temp.release();
|
|
}
|
|
|
|
if (!m_bCrop)
|
|
{
|
|
dib=FixedCut(dib,side);
|
|
//XdPrint("m_bCrop \n");
|
|
}
|
|
}
|
|
|
|
void CAutoCrop::setFill(bool val)
|
|
{
|
|
m_bFill = val;
|
|
}
|
|
|
|
bool CAutoCrop::getFill()
|
|
{
|
|
return m_bFill;
|
|
}
|
|
|
|
void CAutoCrop::setCrop(bool val)
|
|
{
|
|
m_bCrop = val;
|
|
}
|
|
|
|
bool CAutoCrop::getCrop()
|
|
{
|
|
return m_bCrop;
|
|
}
|
|
|
|
Point2f CAutoCrop::RotateP2P(Point2f p, Point2f center, double Angle)
|
|
{
|
|
double h = Angle * M_PI / 180;
|
|
float x = (p.x - center.x) * (float)cos(h) - (p.y - center.y) * (float)sin(h) + center.x;
|
|
float y = (p.y - center.y) * (float)cos(h) + (p.x - center.x) * (float)sin(h) + center.y;
|
|
return Point2f(x, y);
|
|
}
|
|
|
|
void CAutoCrop::RotateImage(Mat & image, RotatedRect rotatedRect, bool bCrop,bool fillBlack)
|
|
{
|
|
Point2f center(image.cols / 2, image.rows / 2);
|
|
Mat rot = getRotationMatrix2D(center, rotatedRect.angle, 1);
|
|
RotatedRect rotated = RotatedRect(center, image.size(), -rotatedRect.angle);
|
|
Rect bbox = rotated.boundingRect();
|
|
Scalar sc;
|
|
if (fillBlack)
|
|
{
|
|
warpAffine(image, image, rot, bbox.size(), CV_INTER_LINEAR,0,image.channels()==3?Scalar(255,255,255):Scalar(255));//CV_INTER_NN
|
|
}
|
|
else
|
|
{
|
|
warpAffine(image, image, rot, bbox.size(), CV_INTER_LINEAR,0,Scalar(0));//CV_INTER_NN
|
|
}
|
|
|
|
if(!bCrop)
|
|
return;
|
|
|
|
Point2f box[4];
|
|
vector<Point2f > vec;
|
|
rotatedRect.points(box);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
box[i] = RotateP2P(box[i], center, -rotatedRect.angle);
|
|
vec.push_back(box[i]);
|
|
}
|
|
|
|
RotatedRect rec = minAreaRect(vec);
|
|
Rect roi = rec.boundingRect();
|
|
Rect rectIm(0, 0, image.cols, image.rows);
|
|
roi = roi & rectIm;
|
|
image = image(roi);
|
|
}
|
|
|
|
int CAutoCrop::ProcessRect(Mat & image, RotatedRect & rotatedRect, vector<Point>& maxContour, double scale, double thresh, int blobAreaSize)
|
|
{
|
|
Mat gray;
|
|
int blockCount = 0;
|
|
if (image.channels() == 3)
|
|
{
|
|
if (scale != 1.0f)
|
|
{
|
|
Size ResImgSiz = Size(image.cols*scale, image.rows*scale);
|
|
resize(image, gray, cv::Size(), scale, scale, 0);
|
|
cvtColor(gray, gray, CV_BGR2GRAY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (scale != 1.0f)
|
|
{
|
|
resize(image, gray, cv::Size(), scale, scale, 0);
|
|
}
|
|
}
|
|
Mat threshold_img;
|
|
threshold(gray, threshold_img, thresh, 255.0, CV_THRESH_BINARY);
|
|
vector<vector<Point>> contours;
|
|
vector<Vec4i> h1;
|
|
GetContours(threshold_img, contours,h1,CV_RETR_EXTERNAL);
|
|
|
|
threshold_img.release();
|
|
if (contours.size() == 0)
|
|
{
|
|
return blockCount;
|
|
}
|
|
|
|
vector<Point> list_com;
|
|
|
|
for (int i = 0; i < contours.size(); i++)
|
|
{
|
|
double area = contourArea(contours[i]);
|
|
|
|
if (area > blobAreaSize)
|
|
{
|
|
blockCount++;
|
|
for (int j = 0; j < contours[i].size(); j++)
|
|
{
|
|
list_com.push_back(contours[i][j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (list_com.size() == 0)
|
|
{
|
|
return blockCount;
|
|
}
|
|
|
|
rotatedRect = minAreaRect(list_com);
|
|
|
|
rotatedRect.center.x /= (float)scale;
|
|
rotatedRect.center.y /= (float)scale;
|
|
rotatedRect.size.width /= (float)scale;
|
|
rotatedRect.size.height /= (float)scale;
|
|
|
|
if (rotatedRect.angle < -45.0f)
|
|
{
|
|
rotatedRect.angle += 90.0f;
|
|
float l_temp = rotatedRect.size.width;
|
|
rotatedRect.size.width = rotatedRect.size.height;
|
|
rotatedRect.size.height = l_temp;
|
|
}
|
|
|
|
vector<int> hull(list_com.size());
|
|
|
|
convexHull(list_com, hull);
|
|
for (int i = 0; i < hull.size(); i++)
|
|
{
|
|
Point temp = list_com[hull[i]];
|
|
int x = (int)(temp.x / scale);
|
|
int y = (int)(temp.y / scale);
|
|
maxContour.push_back(Point(x, y));
|
|
}
|
|
return blockCount;
|
|
}
|
|
|
|
void CAutoCrop::fillBlack(cv::Mat & dib, std::vector<cv::Point>& contour, int edge)
|
|
{
|
|
Mat mask(dib.rows, dib.cols, CV_8UC1);
|
|
if (contour.size() < 3)
|
|
{
|
|
return;
|
|
}
|
|
mask.setTo(255);
|
|
|
|
fillConvexPoly(mask, contour, Scalar(0));//填充轮廓构成的凸多边形
|
|
Mat dilateKer = getStructuringElement(MORPH_RECT, Size(3, 3));
|
|
dilate(mask, mask, dilateKer, Point(-1, -1), edge, BORDER_CONSTANT);//向内腐蚀灰边的宽度
|
|
//imwrite("mask1.bmp",mask);
|
|
dilateKer.release();
|
|
cv::vector<cv::vector<Point>> contours;
|
|
cv::vector<Vec4i> h1;
|
|
GetContours(mask, contours, h1,CV_RETR_LIST);//向内腐蚀后的轮廓
|
|
//XdPrint("GetContours after");
|
|
mask.release();
|
|
|
|
//vector<Point> temp=contours.at(0);
|
|
//const Point* pnt[1]={&temp[0]};
|
|
//int numofPoints=(int)temp.size();
|
|
//for (int i=0;i<contours.size();i++)
|
|
//{
|
|
// for (int j=0;j<contours[i].size();j++)
|
|
// {
|
|
// XdPrint(" X: %d Y: %d \n",contours[i][j].x,contours[i][j].y);
|
|
// }
|
|
//}
|
|
MyFillPoly(dib,contours,cv::Scalar::all(255));
|
|
}
|
|
|
|
Mat CAutoCrop::AutomaticDeskew(Mat image,int thres,float scale)
|
|
{
|
|
RotatedRect rotatedRect;
|
|
vector<Point> contour;
|
|
RotateImage(image, rotatedRect);
|
|
//XdPrint("AutomaticDeskew");
|
|
return image;
|
|
}
|
|
|
|
Mat CAutoCrop::FixedCut(Mat image,int side)
|
|
{
|
|
Size szActual;
|
|
szActual.width=m_dstSize.cx;
|
|
szActual.height=m_dstSize.cy;
|
|
Size szOrg;
|
|
szOrg.width=m_originSize.cx;
|
|
szOrg.height=m_originSize.cy;
|
|
|
|
Rect rectCrop;
|
|
rectCrop.x = (image.cols- szOrg.width) / 2 ;
|
|
rectCrop.y = 0;
|
|
rectCrop.width = szOrg.width;
|
|
rectCrop.height = szOrg.height;
|
|
Rect rectImage(0, 0, image.cols, image.rows);
|
|
if (side != 0)
|
|
{
|
|
rectCrop.y = 143; //调整反面
|
|
}else
|
|
{
|
|
rectCrop.y = 73; //调整正面
|
|
}
|
|
Size CropOrg = (rectCrop & rectImage).size ();
|
|
Mat roi = image(rectCrop);
|
|
//XdPrint("FixedCut");
|
|
return roi;
|
|
}
|
|
|
|
//void CAutoCrop::fillrect(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType, int shift, Point offset)
|
|
//{
|
|
// int i, ncontours = (int)pts.total();
|
|
// if( ncontours == 0 )
|
|
// return;
|
|
// AutoBuffer<Point*> _ptsptr(ncontours);
|
|
// AutoBuffer<int> _npts(ncontours);
|
|
// Point** ptsptr = _ptsptr.data();
|
|
// int* npts = _npts.data();
|
|
//
|
|
// for( i = 0; i < ncontours; i++ )
|
|
// {
|
|
// Mat p = pts.getMat(i);
|
|
// CV_Assert(p.checkVector(2, CV_32S) >= 0);
|
|
// ptsptr[i] = p.ptr<Point>();
|
|
// npts[i] = p.rows*p.cols*p.channels()/2;
|
|
// }
|
|
// fillPoly(img, (const Point**)ptsptr, npts, (int)ncontours, color, lineType, shift, offset);
|
|
//}
|
|
|
|
int CAutoCrop::range(int low, int up, int value)
|
|
{
|
|
if (low > up)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
if (value < low)
|
|
{
|
|
return low;
|
|
}
|
|
|
|
if (value > up)
|
|
{
|
|
return up;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void CAutoCrop::GetContours(const Mat& src, vector<vector<Point>>& contours, vector<Vec4i>& hierarchy, int retr /*= RETR_CCOMP*/)
|
|
{
|
|
CvMat c_image = src;
|
|
MemStorage storage(cvCreateMemStorage());
|
|
CvSeq* _ccontours = 0;
|
|
cvFindContours(&c_image, storage, &_ccontours, sizeof(CvContour), retr, CHAIN_APPROX_SIMPLE);
|
|
|
|
if (!_ccontours)
|
|
{
|
|
contours.clear();
|
|
return;
|
|
}
|
|
Seq<CvSeq*> all_contours(cvTreeToNodeSeq(_ccontours, sizeof(CvSeq), storage));
|
|
int total = (int)all_contours.size();
|
|
contours.resize(total);
|
|
|
|
SeqIterator<CvSeq*> it = all_contours.begin();
|
|
for (int i = 0; i < total; i++, ++it)
|
|
{
|
|
CvSeq* c = *it;
|
|
((CvContour*)c)->color = (int)i;
|
|
int count = (int)c->total;
|
|
int* data = new int[count * 2];
|
|
cvCvtSeqToArray(c, data);
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
contours[i].push_back(Point(data[j * 2], data[j * 2 + 1]));
|
|
}
|
|
delete[] data;
|
|
}
|
|
|
|
hierarchy.resize(total);
|
|
it = all_contours.begin();
|
|
for (int i = 0; i < total; i++, ++it)
|
|
{
|
|
CvSeq* c = *it;
|
|
int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1;
|
|
int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1;
|
|
int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1;
|
|
int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1;
|
|
hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev);
|
|
}
|
|
}
|
|
|
|
|
|
void CAutoCrop::MyFillPoly(Mat& img, vector<vector<Point>> contours, const Scalar& color, int lineType, int shift, Point offset)
|
|
{
|
|
Point** ptsptr = new Point*[contours.size()];
|
|
int length1 = contours.size();
|
|
int* npts = new int[length1];
|
|
for (size_t i = 0; i < length1; i++)
|
|
{
|
|
int length2 = contours[i].size();
|
|
npts[i] = length2;
|
|
ptsptr[i] = new Point[length2];
|
|
for (size_t j = 0; j < length2; j++)
|
|
{
|
|
ptsptr[i][j] = contours[i][j];
|
|
}
|
|
}
|
|
|
|
fillPoly(img, (const Point**)ptsptr, npts, length1, color, lineType, shift, offset);
|
|
|
|
for (size_t i = 0; i < length1; i++)
|
|
{
|
|
delete[] ptsptr[i];
|
|
}
|
|
delete[] ptsptr;
|
|
delete[] npts;
|
|
} |