一 实现步骤
1. 使用imread()加载原图
2. 对原图进行二值化
3. 统计垂直方向和水平方向的直方图
4. 把直方图投影到Mat上
5. 从直方图分割字符
二 关键代码
1 加载原图
void MainWindow::on_tbImagePath_clicked()
{
//选择原图
QFileDialog dlg(this, tr("打开文件"), homeDir(),
"Image Files(*.bmp *.jpg *.jpeg *png);;BMP Files(*.bmp);;JPG Files(*.jpg *.jpeg);;PNG File(*.png);;All Files(*)");
dlg.setFileMode(QFileDialog::ExistingFile);
dlg.setAcceptMode(QFileDialog::AcceptOpen);
QString sText;
if (dlg.exec() == QDialog::Accepted)
{
sText = dlg.selectedFiles()[0];
ui->leImagePath->setText(sText);
}
//1. 加载原图
if (!sText.isEmpty())
{
m_matSrc = imread(sText.toLatin1().data(), IMREAD_COLOR);
showImage();
}
}
2 对原图进行二值化
void MainWindow::showImage()
{
if (m_matSrc.empty()) return;
m_pScene->clear();
//1. 转成灰度图
Mat matGray;
cvtColor(m_matSrc, matGray, CV_RGB2GRAY);
//2. 把灰度图转成二值图
threshold(matGray, m_matBin, m_iThreshold, 255, THRESH_BINARY);
imwrite("/home/mark/Desktop/matBin.bmp", m_matBin);
int w = m_matSrc.cols;
int h = m_matSrc.rows;
if (m_pScene->width() != w || m_pScene->height() != h)
{
m_pScene->setSceneRect(0, 0, w, h);
ui->graphicsView->setScene(m_pScene);
}
QPixmap pix;
if (m_bShowWho)
{
pix = mat2Pixmap(&m_matSrc);
}
else
{
pix = mat2Pixmap(&m_matBin);
}
m_pScene->addPixmap(pix);
//投影直方图 分割字符
shadowHistogram();
}
3 统计垂直方向和水平方向的直方图
//水平方向投影直方图
void MainWindow::hShadowHistogram(int *&pHorizontal)
{
if (m_matBin.empty()) return;
int w = m_matBin.cols;
int h = m_matBin.rows;
pHorizontal = new int[h]; //创建一个用于储存每行黑色像素个数的数组
memset(pHorizontal, 0, sizeof(int) * m_matBin.rows);
//遍历每一行的图像灰度值,查找每一列0的值
for (int iRow = 0; iRow < h; iRow++)
{
for (int iCol = 0; iCol < w; iCol++)
{
uchar perPixelValue = m_matBin.at
if (perPixelValue == 0)//如果是白底黑字
{
pHorizontal[iRow]++;
}
}
}
//新建一个Mat用于储存投影垂直方向直方图并将背景置为黑
Mat matHorizontal(h, w, CV_8UC1, Scalar(0));
//将直方图的曲线设为白色
for (int i = 0; i < h; i++)
{
for (int j = 0; j < pHorizontal[i]; j++)
{
//matHorizontal.at
matHorizontal.at
}
}
namedWindow("H");
imshow("H", matHorizontal);
}
//垂直方向投影直方图
void MainWindow::vShadowHistogram(int *&pVertical)
{
if (m_matBin.empty()) return;
int w = m_matBin.cols;
int h = m_matBin.rows;
pVertical = new int[w]; //创建一个用于储存每列黑色像素个数的数组
memset(pVertical, 0, sizeof(int) * m_matBin.cols);
//遍历每一列的图像灰度值,查找每一行0的值
for (int iCol = 0; iCol < w; iCol++)
{
for (int iRow = 0; iRow < h; iRow++)
{
uchar perPixelValue = m_matBin.at
if (perPixelValue == 0)//如果是白底黑字
{
pVertical[iCol]++;
}
}
}
//新建一个Mat用于储存投影垂直方向直方图并将背景置为黑
Mat matVertical(h, w, CV_8UC1, Scalar(0));
//将直方图的曲线设为白色
for (int i = 0; i < w; i++)
{
for (int j = 0; j < pVertical[i]; j++)
{
//matVertical.at
matVertical.at
}
}
namedWindow("V");
imshow("V", matVertical);
}
4 把直方图投影到Mat上
//投影直方图
void MainWindow::shadowHistogram()
{
if (m_matBin.empty()) return;
Mat matDraw = m_matSrc.clone();
//1 投影直方图
int* pHorizontal = NULL;
int* pVertical = NULL;
hShadowHistogram(pHorizontal); //投影水平方向直方图
vShadowHistogram(pVertical); //投影垂直方向直方图
//2 根据直方图 分割字符
int w = m_matBin.cols;
int h = m_matBin.rows;
QList
bool bBlock = false;//是否遍历到了字符区内
if (pHorizontal)
{
int iStartY = 0; //记录进入字符区的索引
int iEndY = 0; //记录进入空白区域的索引
for (int i = 0; i < h; i++)
{
if (!bBlock && pHorizontal[i] != 0)//进入字符区了
{
bBlock = true;
iStartY = i;
QLine line1(QPoint(0, iStartY), QPoint(w, iStartY));
hLine << line1;
m_pScene->addLine(line1, QPen(QColor(255, 0, 0)));
line(matDraw, Point(0, iStartY), Point(w-1, iStartY), Scalar(0, 0, 255));
}
else if (bBlock && pHorizontal[i] == 0)
{
iEndY = i;
bBlock = false;
QLine line2(QPoint(0, iEndY), QPoint(w, iEndY));
hLine << line2;
m_pScene->addLine(line2, QPen(QColor(255, 0, 0)));
line(matDraw, Point(0, iEndY), Point(w-1, iEndY), Scalar(0, 0, 255));
}
}
}
QList
bBlock = false;//是否遍历到了字符区内
if (pVertical)
{
int iStartX = 0; //记录进入字符区的索引
int iEndX = 0; //记录进入空白区域的索引
for (int i = 0; i < w; i++)
{
if (!bBlock && pVertical[i] != 0)//进入字符区了
{
bBlock = true;
iStartX = i;
QLine line1(QPoint(iStartX, 0), QPoint(iStartX, h));
vLine << line1;
m_pScene->addLine(line1, QPen(QColor(0, 255, 0)));
line(matDraw, Point(iStartX, 0), Point(iStartX, h-1), Scalar(0, 255, 0));
}
else if (bBlock && pVertical[i] == 0)
{
iEndX = i;
bBlock = false;
QLine line2(QPoint(iEndX, 0), QPoint(iEndX, h));
vLine << line2;
m_pScene->addLine(line2, QPen(QColor(0, 255, 0)));
line(matDraw, Point(iEndX, 0), Point(iEndX, h-1), Scalar(0, 255, 0));
}
}
}
imwrite("/home/mark/Desktop/matDraw.bmp", matDraw);
MYDELETES(pHorizontal);
MYDELETES(pVertical);
}
三 测试结果
测试结果1:
测试结果2
四 源码链接
https://download.csdn.net/download/cwj066/10859928