因為要做圖像處理方面的工作,是以最近在學習OpenCv的使用,學習了OpenCv中Mat對象的相關使用之後,實作了使用Mat對象來進行圖像的水準投影和垂直投影,并且在投影之後,對字元進行相對應的切分。現在将相關代碼貼出,一來可以供大家參考并指正錯誤,而來也為的是防止忘記了相關知識。以下就是程式的代碼,歡迎大家指正錯誤。
#include <stdafx.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
vector<Mat> horizontalProjectionMat(Mat srcImg)//水準投影
{
Mat binImg;
blur(srcImg, binImg, Size(3, 3));
threshold(binImg, binImg, 0, 255, CV_THRESH_OTSU);
int perPixelValue = 0;//每個像素的值
int width = srcImg.cols;
int height = srcImg.rows;
int* projectValArry = new int[height];//建立一個儲存每行白色像素個數的數組
memset(projectValArry, 0, height * 4);//初始化數組
for (int col = 0; col < height; col++)//周遊每個像素點
{
for (int row = 0; row < width; row++)
{
perPixelValue = binImg.at<uchar>(col, row);
if (perPixelValue == 0)//如果是白底黑字
{
projectValArry[col]++;
}
}
}
Mat horizontalProjectionMat(height, width, CV_8UC1);//建立畫布
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perPixelValue = 255;
horizontalProjectionMat.at<uchar>(i, j) = perPixelValue;//設定背景為白色
}
}
for (int i = 0; i < height; i++)//水準直方圖
{
for (int j = 0; j < projectValArry[i]; j++)
{
perPixelValue = 0;
horizontalProjectionMat.at<uchar>(i, width - 1 - j) = perPixelValue;//設定直方圖為黑色
}
}
vector<Mat> roiList;//用于儲存分割出來的每個字元
int startIndex = 0;//記錄進入字元區的索引
int endIndex = 0;//記錄進入空白區域的索引
bool inBlock = false;//是否周遊到了字元區内
for (int i = 0; i <srcImg.rows; i++)
{
if (!inBlock && projectValArry[i] != 0)//進入字元區
{
inBlock = true;
startIndex = i;
}
else if (inBlock && projectValArry[i] == 0)//進入空白區
{
endIndex = i;
inBlock = false;
Mat roiImg = srcImg(Range(startIndex, endIndex + 1), Range(0, srcImg.cols));//從原圖中截取有圖像的區域
roiList.push_back(roiImg);
}
}
delete[] projectValArry;
return roiList;
}
vector<Mat> verticalProjectionMat(Mat srcImg)//垂直投影
{
Mat binImg;
blur(srcImg, binImg, Size(3, 3));
threshold(binImg, binImg, 0, 255, CV_THRESH_OTSU);
int perPixelValue;//每個像素的值
int width = srcImg.cols;
int height = srcImg.rows;
int* projectValArry = new int[width];//建立用于儲存每列白色像素個數的數組
memset(projectValArry, 0, width * 4);//初始化數組
for (int col = 0; col < width; col++)
{
for (int row = 0; row < height;row++)
{
perPixelValue = binImg.at<uchar>(row, col);
if (perPixelValue == 0)//如果是白底黑字
{
projectValArry[col]++;
}
}
}
Mat verticalProjectionMat(height, width, CV_8UC1);//垂直投影的畫布
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perPixelValue = 255; //背景設定為白色
verticalProjectionMat.at<uchar>(i, j) = perPixelValue;
}
}
for (int i = 0; i < width; i++)//垂直投影直方圖
{
for (int j = 0; j < projectValArry[i]; j++)
{
perPixelValue = 0; //直方圖設定為黑色
verticalProjectionMat.at<uchar>(height - 1 - j, i) = perPixelValue;
}
}
imshow("垂直投影",verticalProjectionMat);
cvWaitKey(0);
vector<Mat> roiList;//用于儲存分割出來的每個字元
int startIndex = 0;//記錄進入字元區的索引
int endIndex = 0;//記錄進入空白區域的索引
bool inBlock = false;//是否周遊到了字元區内
for (int i = 0; i < srcImg.cols; i++)//cols=width
{
if (!inBlock && projectValArry[i] != 0)//進入字元區
{
inBlock = true;
startIndex = i;
}
else if (projectValArry[i] == 0 && inBlock)//進入空白區
{
endIndex = i;
inBlock = false;
Mat roiImg = srcImg(Range(0, srcImg.rows), Range(startIndex, endIndex + 1));
roiList.push_back(roiImg);
}
}
delete[] projectValArry;
return roiList;
}
int main(int argc, char* argv[])
{
Mat srcImg = imread("E:\\b.png", 0);//讀入原圖像
char szName[30] = { 0 };
vector<Mat> b = verticalProjectionMat(srcImg);//先進行垂直投影
for (int i = 0; i < b.size(); i++)
{
vector<Mat> a = horizontalProjectionMat(b[i]);//水準投影
sprintf(szName,"E:\\picture\\%d.jpg",i);
for (int j = 0; j < a.size(); j++)
{
imshow(szName,a[j]);
IplImage img = IplImage(a[j]);
cvSaveImage(szName, &img);//儲存切分的結果
}
}
/*
vector<Mat> a = horizontalProjectionMat(srcImg);
char szName[30] = { 0 };
for (int i = 0; i < a.size(); i++)
{
vector<Mat> b = verticalProjectionMat(a[i]);
for (int j = 0; j<b.size();j++)
{
sprintf(szName, "E:\\%d.jpg", j);
imshow(szName, b[j]);
}
}
*/
cvWaitKey(0);
getchar();
return 0;
}
以下是程式的結果截圖:
(1)原始圖像
(2)垂直投影
(3)水準投影
(4)字元切分
由于水準切分的結果隻有一個,而垂直切分的結果有多個,是以應該要先進行垂直切分,然後再進行水準切分,這樣得到的結果才是切分出字元的大小。若是先進行水準切分,而後進行垂直切分的話,得到的結果就并非要切割出的字元的大小,改代碼已經給出,即注釋掉的代碼,而先進行水準切分,再進行垂直切分的結果如下圖所示:
(5)先水準後垂直
可以看到,有的切分出的圖像,上下仍然有空白的地方。是以,先水準後垂直的切分方法不适合于本程式的要求。
以上是本人的一點見解,有什麼不正确的地方,歡迎指正。