垂直投影算法——OpenCV3.1.0和C++实现——分割图像

                                      对文本中的多行进行分割   


直接上代码

#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<iostream>
#include <stdio.h>
using namespace std;
using namespace cv;

Mat vertical_projection(Mat input_src) //基于Y轴垂直投影分割算法(输入的是二值图像)
{
	/**************统计原图片中每行黑色像素数目******************************/

	blur(input_src, input_src, Size(3, 3));//对输入的二值图像进行3*3均值滤波(blur是均值滤波函数)
	int src_width = input_src.cols;        //获得二值图像的列数(宽)(列的像素点个数)
	int src_height = input_src.rows;       //获得二值图像的行数(高)(行的像素点个数)
	int* projectValArry = new int[src_height]();//创建用于储存每行黑色像素个数的数组
	//在行的基础下遍历每一列,取列黑色像素个数,获得储存每行黑色像素个数的数组
	for (int i = 0; i < src_height; i++){
		for (int j = 0; j < src_width; j++){
			if (input_src.at<uchar>(i, j) == 0)      //at:取出二值图像的i行j列的像素点,如果他是黑色,则存取
			{
				projectValArry[i]++;   //每一行的黑色像素个数加一
			}
		}
	}
	for (int i = 0; i < src_height; i++)   //验证下每行存的值(应该是有0的)
	{
		cout << projectValArry[i] << endl;
	}
	/**************将每行黑色像素数目绘制成直方图***************************/

	//定义画布 绘制Y轴垂直投影下每行黑色像素的数目
	Mat verticalProjectionMat(src_height, src_width, CV_8UC1, Scalar(255));   //定义一个和原图像大小相同的全1(白色)的画布图像
	for (int i = 0; i< src_height; i++){
		for (int j = 0; j < projectValArry[i]; j++){
			verticalProjectionMat.at<uchar>(i, j) = 0;   //在图像左侧绘制直方图
		}
	}
	imshow("verticalProjectionMat", verticalProjectionMat);  //显示直方图(往Y-轴投影的直方图)
	imwrite("image_histogram.png", verticalProjectionMat);
	/*********根据每列白色像素数目设置截取起始和截止列***********************/

	//定义Mat vector ,存储图片数组
	vector<Mat> split_src;
	//定义标志,用来指示在白色像素区还是在全黑区域
	bool white_block = 0, black_block = 0;
	//定义列temp_col_forword  temp_col_behind,记录字符截取起始行和截止行
	int temp_row_forword = 0, temp_row_behind = 0;
	Mat split_temp;
	//遍历数组projectValArry
	for (int i = 0; i < src_height; i++){
		if (projectValArry[i]){//表示区域有黑色像素
			white_block = 0;
			black_block = 1;
		}
		else{				//若无黑色像素(进入白色区域)
			if (black_block == 1){//若前一列有黑色像素
				temp_row_behind = i;//取当前列为截止列
				//截取下一部分
				//clone:把input_src(Rect()),即矩形区域内的信息完全拷贝给split_temp,是Mat类型
				split_temp = input_src(Rect(0, temp_row_forword-5, src_width, temp_row_behind - temp_row_forword+10)).clone();
				split_src.push_back(split_temp);   //将此区域Mat存到Mat数组中
			}
			temp_row_forword = i;//记录最新白色区域的列号,记为起始列
			black_block = 0;//表示进入白色区域
			white_block = 1;
		}
	}

	/*********显示分割后的每个图片***********************/

	for (int i = 0; i < split_src.size(); i++){
		char window[20];
		sprintf(window, " split: %d", i);
		imshow(window, split_src[i]);   //显示分割后的图片
		string imagename = "D:\\soft\\VS2013\\Project-test\\test_opencv\\test_opencv\\"+ to_string(i) + ".png";
		imwrite(imagename.c_str(), split_src[i]);  //保存图片
	}
	waitKey(0);
	return input_src;
}

int main()
{
	Mat srcImage = imread("C:\\Users\\12534\\Desktop\\2.png");
	imshow("Original_image", srcImage);
	if (!srcImage.data){
		cout << "failed to read" << endl;   //如果读取不了Mat中的数据,则打印读取失败
		system("pause");
		return -1;
	}
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_BGR2GRAY);    //将传入的BGR图片转换成灰度图片 
	Mat bin_src;
	threshold(srcGray, bin_src, 100, 255, CV_THRESH_OTSU); //基于最大类间方差法(otsu)(获得最佳阈值)的图像二值化
	imshow("bin_src", bin_src);   //显示二值图像
	imwrite("bin_src.png", bin_src);
	vertical_projection(bin_src);
	waitKey(0);
	return 0;
}
  • 原图像

  • 二值图像(bin_src.png)

  • 二值图像的直方图(image_histogram.png)

  • 分割后的图片

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章