垂直投影算法——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)

  • 分割後的圖片

 

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