1. 程式人生 > >OpenCV影象角度矯正

OpenCV影象角度矯正

影象角度矯正原始碼

/高升教我的一二三事
#include<iostream>
#include<string>
#include<sstream>
#include"dllpic.h"
using namespace std;
#include "opencv2/opencv.hpp"
using namespace cv;
int _stdcall Add(int n1, int n2) {
// int  Add(int n1, int n2) {
	return (n1 + n2);
}

int _stdcall Minus(int n1, int n2) {
	// int  Add(int n1, int n2) {
	return (n1 - n2);
}

//方法-
  double cvMatImageSkewAngleUsingSHT(cv::Mat gray)
{
	// Load in grayscale.
	//cv::Mat src = cv::imread(filename, cv::IMREAD_GRAYSCALE)
	if (gray.data == NULL) {
		fprintf(stderr, "error: src.data == NULL\n");
		return 0.0f;
	}
	if (gray.channels() != 1) {
		fprintf(stderr, "error: src.channels() != 1\n");
		return 0.0f;
	}
	cv::bitwise_not(gray, gray);

	cv::Size size = gray.size();

	// 需要的是黑色背景
	std::vector<cv::Vec4i> lines;
	cv::HoughLinesP(gray, lines, 1, CV_PI / 180, 100, size.width / 2.f, 20);
	cv::Mat disp_lines(size, CV_8UC1, cv::Scalar(0, 0, 0));
	double angle = 0.;
	unsigned nb_lines = lines.size();
	for (unsigned i = 0; i < nb_lines; ++i)
	{
		cv::line(disp_lines, cv::Point(lines[i][0], lines[i][1]), cv::Point(lines[i][2], lines[i][3]), cv::Scalar(255, 0, 0));
		angle += atan2((double)lines[i][3] - lines[i][1], (double)lines[i][2] - lines[i][0]);
	}
	angle /= nb_lines; // mean angle, in radians.
	angle = angle * 180 / CV_PI;
	cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle1.bmp", disp_lines);

	fprintf(stderr, "ImageSkewAngle result: %f\n", angle);

	return angle;
}

  //方法二
  double cvMatImageSkewAngleWithImageBin(cv::Mat image_bin)
  {
	  // 輸入的是黑底白字圖片
	  cv::Mat image = image_bin.clone();
	  if (image.data == NULL) {
		  fprintf(stderr, "error: src.data == NULL\n");
		  return 0.0f;
	  }
	  if (image.channels() != 1) {
		  fprintf(stderr, "error: src.channels() != 1\n");
		  return 0.0f;
	  }
	  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle2.bmp", image);

	  // Size(23, 3)); Size(5, 3));,使用Size(3, 3)最好
	  cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3));
	  // 最基本的形態學操作有二:腐蝕與膨脹(Erosion 與 Dilation)
	  cv::erode(image, image, element);

	  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle3.bmp", image);

	  std::vector<cv::Point> points;
	  cv::Mat_<uchar>::iterator it = image.begin<uchar>();
	  cv::Mat_<uchar>::iterator end = image.end<uchar>();
	  for (; it != end; ++it)
		  if (*it)
			  points.push_back(it.pos());

	  cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));


	  double angle = box.angle;
	  if (angle < -45.)
		  angle += 90.;

	  if (1) {
		  cv::Point2f vertices[4];
		  box.points(vertices);
		  for (int i = 0; i < 4; ++i)
			  cv::line(image, vertices[i], vertices[(i + 1) % 4], cv::Scalar(255, 0, 0), 1, CV_AA);
		  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle4.bmp", image);

	  }


	  fprintf(stderr, "ImageSkewAngle result: %f\n", angle);

	  return angle;
  }

  cv::Mat cvMatImageSkewAngleWithImageGray(cv::Mat image_gray)
  {
	  // 輸入的是灰度圖片
	  // Load in grayscale.
	  //cv::Mat img = cv::imread(filename, cv::IMREAD_GRAYSCALE);

	  cv::Mat image = image_gray.clone();
	  if (image.data == NULL) {
		  fprintf(stderr, "error: src.data == NULL\n");
		  return cv::Mat();
	  }
	  if (image.channels() != 1) {
		  fprintf(stderr, "error: src.channels() != 1\n");
		  return cv::Mat();
	  }

	  //中值濾波器是一種非線性濾波器,常用於消除影象中的椒鹽噪聲。與低通濾波不同的是,中值濾波有利於保留邊緣的尖銳度,但它會洗去均勻介質區域中的紋理。
	  //cv::medianBlur(img, img, 3);

	  //cv::GaussianBlur(img, img, cv::Size(3, 3), 0);
	  //GaussianBlur(img, img, cvSize(11,11), 0);//change from median blur to gaussian for more accuracy of square detection

	  // Binarize
	  //cv::threshold(img, img, 225, 255, CV_THRESH_BINARY_INV);
	  cv::threshold(image, image, 0, 255, CV_THRESH_OTSU + CV_THRESH_BINARY); // 二值化效果好

	  
	  return image;
  }

  cv::Mat cvMatImageDeskew(cv::Mat src , double angle)
  {
	  cv::Mat img = src.clone();
	  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle6.bmp", img);

	  cv::Mat cropped;
	  cv::Mat rotated;
	  // Load in grayscale.
	  //cv::Mat img = cv::imread(filename, cv::IMREAD_GRAYSCALE);
	  if (img.data == NULL) {
		  fprintf(stderr, "error: src.data == NULL");
		  return rotated;
	  }
	  if (img.channels() != 1) {
		  fprintf(stderr, "error: src.channels() != 1");
		  return rotated;
	  }

	  std::vector<cv::Point> points;
	  cv::Mat_<uchar>::iterator it = img.begin<uchar>();
	  cv::Mat_<uchar>::iterator end = img.end<uchar>();
	  for (; it != end; ++it)
		  if (*it)
			  points.push_back(it.pos());

	  cv::RotatedRect box = cv::minAreaRect(cv::Mat(points));

	  cv::Mat rot_mat = cv::getRotationMatrix2D(box.center, angle, 1);

	  // 旋轉
	  cv::warpAffine(img, rotated, rot_mat, img.size(), cv::INTER_CUBIC); // 預設是黑色背景
																		  //cv::warpAffine(img, rotated, rot_mat, img.size(), CV_INTER_CUBIC, cv::BORDER_CONSTANT, cvScalarAll(0)); // 黑色背景
																		  //cv::warpAffine(img, rotated, rot_mat, img.size(), cv::INTER_CUBIC, cv::BORDER_CONSTANT, cvScalar(255, 255, 255)); // 白色背景

	  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle7.bmp", rotated);
	  if (0) {
		  // 切割
		  cv::Size box_size = box.size;
		  if (box.angle < -45.)
			  std::swap(box_size.width, box_size.height);
		  cv::getRectSubPix(rotated, box_size, box.center, cropped);
		  cv::imwrite("E:/OpenCv/jiaozhengPic/pic/5angle8.bmp", cropped);
	  }
	  return rotated;

  }
  int main(int argc, const char ** argv)
  {
	  double angle = 0; 
	  string  fileStr = "E:/OpenCv/jiaozhengPic/pic/5angle.bmp";
	  Mat src = imread(fileStr, 0);
	  Mat gray = imread(fileStr, 0);
	  angle = cvMatImageSkewAngleUsingSHT(gray);
	  //方法二
	  /*bitwise_not(gray, gray);
	    gray = cvMatImageSkewAngleWithImageGray(gray);
	    angle = cvMatImageSkewAngleWithImageBin(gray);
      */
	  cvMatImageDeskew(src, angle);
	  return 0;
  }