一,原图
二,分割成行
三,通过旋转,切割后的效果(无透视变换)
四,通过旋转,透视变换,切割后的效果
五,源代码,
//初始化透视变换全局变量
Mat warpMatrix;
//计算透视变换矩阵
void InitPersTransfor()
{
vector<Point> not_a_rect_shape;
not_a_rect_shape.push_back(Point(3, 82));
not_a_rect_shape.push_back(Point(2, 276));
not_a_rect_shape.push_back(Point(234, 191));
not_a_rect_shape.push_back(Point(239, 1));
// For debugging purposes, draw green lines connecting those points
// and save it on disk
const Point* point = ¬_a_rect_shape[0];
int n = (int)not_a_rect_shape.size();
//Mat draw = ImgCut.clone();
//polylines(draw, &point, &n, 1, true, Scalar(0, 255, 0), 3, CV_AA);
//imwrite("draw.jpg", draw);
// topLeft, topRight, bottomRight, bottomLeft
cv::Point2f src_vertices[4];
src_vertices[0] = not_a_rect_shape[0];
src_vertices[1] = not_a_rect_shape[1];
src_vertices[2] = not_a_rect_shape[2];
src_vertices[3] = not_a_rect_shape[3];
Point2f dst_vertices[4];
dst_vertices[0] = Point(2, 2);
dst_vertices[1] = Point(0, 194);
dst_vertices[2] = Point(235, 190);
dst_vertices[3] = Point(239, 1);
warpMatrix = getPerspectiveTransform(src_vertices, dst_vertices);
}
//斜体分割
void MyCutImageItalic(Mat src, int iImgNO, CString C_SavePath, bool bSave)
{
//--------------旋转------------------------------------------------------
double angle = 19;
Point2f center(src.cols / 2, src.rows / 2);
Mat rot = getRotationMatrix2D(center, angle, 1);
Rect bbox = RotatedRect(center, src.size(), angle).boundingRect();
rot.at<double>(0, 2) += bbox.width / 2.0 - center.x;
rot.at<double>(1, 2) += bbox.height / 2.0 - center.y;
//设置选择背景边界颜色:白色
Scalar borderColor = Scalar(255, 255, 255);
Mat dst;
warpAffine(src, dst, rot, bbox.size(), INTER_LINEAR, BORDER_CONSTANT, borderColor);
Mat gray, BinImg;
if (dst.channels() == 3)
{
cvtColor(dst, gray, CV_BGR2GRAY); //转换成灰度图
}
else
{
gray = dst;
}
//--------------旋转------------------------------------------------------
//--------------垂直投影--------------------------------------------------
threshold(gray, BinImg, 166, 255, CV_THRESH_BINARY); //整个图像进行二值化
Mat lineImg(1, BinImg.cols, CV_8UC1, cv::Scalar(0, 0, 0)); //生成一维图像,高是1,宽是原图列数
lineImg = VerticalProjection(BinImg);
//---------------判断峰值的开始结束位置-------------------------
vector<int> ivecBegin; //开始
vector<int> ivecEnd; //结束
int icount = 0; //统计峰值数
int ibegin = 666666; //开始位置
int iend = 666666; //结束位置
int minVal = 2; //判断的基准值
int minSpace = 6; //最小间距
bool bbegin = false; //判断峰值是否在最左边
int value = 0; //图像像素值
for (int i = 0; i < lineImg.cols; i++)
{
value = lineImg.at<uchar>(0, i);
//=======排除最左边峰值干扰=============
if (value > minVal&&i == 0)
{
bbegin = true;
}
if (value < minVal&&bbegin == true)
{
bbegin = false;
}
//=======排除最左边峰值干扰=============
if (value > minVal && ibegin == 666666 && bbegin == false)//bbegin == false可排除最左边未切割干净的字符
{
ibegin = i; //开始位置
}
else if (value<minVal&&ibegin != 666666 && (i - ibegin)>minSpace)
{
icount++; //统计数加1
iend = i; //结束位置
ivecBegin.push_back(ibegin); //加入容器
ivecEnd.push_back(iend); //加入容器
ibegin = 666666; //复位
iend = 666666; //复位
}
else if (value>minVal&&ibegin != 666666 && i == lineImg.cols - 1) //峰值在最右边情况
{
icount++; //统计数加1
iend = i; //结束位置
ivecBegin.push_back(ibegin); //加入容器
ivecEnd.push_back(iend); //加入容器
ibegin = 666666; //复位
iend = 666666; //复位
}
else
{
}
} //for (int i = 0; i < lineImg.cols; i++)
//---------------判断峰值的开始结束位置-------------------
//--------------垂直投影--------------------------------------------------
for (int i = 0; i < ivecEnd.size(); i++)
{
Mat ImgCut = BinImg(Rect(ivecBegin[i] - 1, 0, ivecEnd[i] - ivecBegin[i] + 1, BinImg.rows)); //选择二值化图像部分
Mat ImgCutgray = gray(Rect(ivecBegin[i] - 1, 0, ivecEnd[i] - ivecBegin[i] + 1, BinImg.rows)); //选择灰度图像部分
//-------------------透视变换校正-----------------------------------------------------
cv::Mat rotated, rotatedgray;
//设置选择背景边界颜色:白色
Scalar borderColor2 = Scalar(255, 255, 255);
warpPerspective(ImgCut, rotated, warpMatrix, rotated.size(), INTER_LINEAR, BORDER_CONSTANT, borderColor2);
warpPerspective(ImgCutgray, rotatedgray, warpMatrix, rotatedgray.size(), INTER_LINEAR, BORDER_CONSTANT, borderColor2);
//-------------------透视变换校正-----------------------------------------------------
//-------------------先做一下水平投影,去除多余空白-----------------------------------
Mat rotatedCopy;
rotated.copyTo(rotatedCopy);
Mat HorImg = HorProjection(rotatedCopy); //水平投影
int ibeginrow = 0; //开始行
int iendrow = 0; //结束行
bool bbeginrow = false;
bool bendrow = false;
bool bHorFengzhi = false; //水平方向是否有峰值
for (int i = 0; i < HorImg.rows; i++)
{
if (HorImg.at<uchar>(i, 0) != 0 && bbeginrow == false) //正向搜索
{
ibeginrow = i;
bbeginrow = true;
}
if (HorImg.at<uchar>(HorImg.rows - i - 1, 0) != 0 && bendrow == false) //反向搜索
{
iendrow = HorImg.rows - i - 1;
bendrow = true;
}
}
Mat imgSave = rotatedgray(Rect(0, ibeginrow, ImgCut.cols, iendrow - ibeginrow + 1));
//-------------------先做一下水平投影,去除多余空白-----------------------------------
if (bSave == true)
{
CString CTemp;
CTemp.Format(_T("%s%d_%d.jpg"), C_SavePath,iImgNO, i + 1);
string strImgPath = (CW2A(CTemp.GetString()));
imwrite(strImgPath, imgSave);
}
} // for (int i = 0; i < ivecEnd.size(); i++)
}
//读取待分割图像
bool CCutImageVS2013Dlg::MyClassifiReadImageItalic()
{
//初始化透视变换
InitPersTransfor();
CWnd* pWnd = AfxGetMainWnd();//
CString C_SavePath, C_readImgPath;
int NUM = 0; //读图图片数量
pWnd->GetDlgItem(IDC_ImgNum_EDIT)->GetWindowTextW(m_ImgNumVal);//获取控件中的参数值
NUM = _wtoi(m_ImgNumVal); //传给全局变量
if (NUM == 0)
{
AfxMessageBox(_T("请输入图像数量!"));
return false;
}
Mat image;
int iImgNO = 1;
CString C_str;
int iType = 66;
//##########判断文件夹存不存在###########################
if (nSel == 0)
{
C_readImgPath = "D:\\sxl\\处理图片\\斜体分割\\1lineImage\\"; //读取图像路径
C_SavePath = "D:\\sxl\\处理图片\\斜体分割\\1lineImage处理\\";
//------------方便查看结果-------------
C_FilePath = C_SavePath;
//------------方便查看结果-------------
//strPath0.Format(_T("%s\\"), C_Str0);
if (!PathFileExists(C_SavePath))
{
system("md D:\\sxl\\处理图片\\斜体分割\\1lineImage处理\\");
}
}
int icount = 0;
int iID = 0;
while (iImgNO <= NUM) //
{
//#############################################
CString C_Status;
C_Status.Format(_T("正在处理第%d张图,共%d张!"), iImgNO, NUM);
pWnd->GetDlgItem(IDC_Status_EDIT)->SetWindowTextW(C_Status);
pWnd->UpdateWindow();
//#############################################
if ((iImgNO-icount*21) == 22)
{
icount++;
iID = 0;
}
iID++;
C_str.Format(_T("%s%d_%d.jpg"), C_readImgPath, icount, iID); //读取图像路径
string strImgPath = (CW2A(C_str.GetString()));
image = imread(strImgPath, 0);//读取图片
if (image.data == 0)
{
AfxMessageBox(_T("没有图片!"));
return false;
}
else
{
//#####处理图像####################
Mat imageCopy;
image.copyTo(imageCopy);
MyCutImageItalic(image, iImgNO, C_SavePath, true);
//#####处理图像####################
}
iImgNO++;
}
AfxMessageBox(_T("运行结束!"));
return true;
}