OpenCV学习笔记__入门篇(三)

来源:互联网 发布:淘宝能赚钱有几个 编辑:程序博客网 时间:2024/05/09 15:49
11、霍夫线变换:使用OpenCV的以下函数 HoughLines 和 HoughLinesP 来检测图像中的直线.
霍夫线变换是一种用来寻找直线的方法。
是用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像。

OpenCV实现了以下两种霍夫线变换:
 标准霍夫线变换
    - 原理在上面的部分已经说明了. 它能给我们提供一组参数对 (\theta, r_{\theta}) 的集合来表示检测到的直线
    - 在OpenCV 中通过函数 HoughLines 来实现
    
 统计概率霍夫线变换
    - 这是执行起来效率更高的霍夫线变换. 它输出检测到的直线的端点 (x_{0}, y_{0}, x_{1}, y_{1})
    - 在OpenCV 中它通过函数 HoughLinesP 来实现

步骤:
Canny( );  边缘检测
cvtColor( );
vector<Vec2f> lines;
HoughLines( );
line( );

代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void help()
{
 cout << "\nThis program demonstrates line finding with the Hough transform.\n"
  "Usage:\n"
  "./houghlines <image_name>, Default is pic1.jpg\n" << endl;
}
int main(int argc, char** argv)
{
 const char* filename = argc >= 2 ? argv[1] : "e:\\jay.jpg";
 Mat src = imread(filename, 0);
 if (src.empty())
 {
  help();
  cout << "can not open " << filename << endl;
  return -1;
 }
 Mat dst, cdst;
 Canny(src, dst, 50, 200, 3);
 cvtColor(dst, cdst, CV_GRAY2BGR);
#if 0
 vector<Vec2f> lines;
 HoughLines(dst, lines, 1, CV_PI / 180, 100, 0, 0);
 for (size_t i = 0; i < lines.size(); i++)
 {
  float rho = lines[i][0], theta = lines[i][1];
  Point pt1, pt2;
  double a = cos(theta), b = sin(theta);
  double x0 = a*rho, y0 = b*rho;
  pt1.x = cvRound(x0 + 1000 * (-b));
  pt1.y = cvRound(y0 + 1000 * (a));
  pt2.x = cvRound(x0 - 1000 * (-b));
  pt2.y = cvRound(y0 - 1000 * (a));
  line(cdst, pt1, pt2, Scalar(0, 0, 255), 3, CV_AA);
 }
#else
 vector<Vec4i> lines;
 HoughLinesP(dst, lines, 1, CV_PI / 180, 50, 50, 10);
 for (size_t i = 0; i < lines.size(); i++)
 {
  Vec4i l = lines[i];
  line(cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA);
 }
#endif
 imshow("source", src);
 imshow("detected lines", cdst);
 waitKey();
 return 0;
}


      霍夫圆变换
    - 使用OpenCV函数 HoughCircles 在图像中检测圆.

代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

/** @function main */
int main(int argc, char** argv)
{
 Mat src, src_gray;

 /// Read the image
 src = imread("e:\\test_circle.jpg");

 if (!src.data)
 {
  return -1;
 }

 /// Convert it to gray
 cvtColor(src, src_gray, CV_BGR2GRAY);

 /// Reduce the noise so we avoid false circle detection
 GaussianBlur(src_gray, src_gray, Size(9, 9), 2, 2);

 vector<Vec3f> circles;

 /// Apply the Hough Transform to find the circles
 HoughCircles(src_gray, circles, CV_HOUGH_GRADIENT, 1, src_gray.rows / 8, 200, 100, 0, 0);

 /// Draw the circles detected
 for (size_t i = 0; i < circles.size(); i++)
 {
  Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
  int radius = cvRound(circles[i][2]);
  // circle center
  circle(src, center, 3, Scalar(0, 255, 0), -1, 8, 0);
  // circle outline
  circle(src, center, radius, Scalar(0, 0, 255), 3, 8, 0);
 }

 /// Show your results
 namedWindow("Hough Circle Transform Demo", CV_WINDOW_AUTOSIZE);
 imshow("Hough Circle Transform Demo", src);

 waitKey(0);
 return 0;
}


12、重映射
使用OpenCV函数 remap 来实现简单重映射.

remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));

上面用到的重映射函数 remap. 参数说明:

    - src: 源图像
    - dst: 目标图像,与 src 相同大小
    - map_x: x方向的映射参数. 它相当于方法 h(i,j) 的第一个参数
    - map_y: y方向的映射参数. 注意 map_y 和 map_x 与 src 的大小一致。
    - CV_INTER_LINEAR: 非整数像素坐标插值标志. 这里给出的是默认值(双线性插值).
    - BORDER_CONSTANT: 默认

对map_x , map_y 处理的四种方法,即更新重映射矩阵的4种不同方法:
    (1). 

图像宽高缩小一半,并显示在中间:

h(i,j) = ( 2*i - src.cols/2  + 0.5, 2*j - src.rows/2  + 0.5)

所有成对的参数 (i,j) 处理后都符合: \dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4} 和 \dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}

    (2). 

图像上下颠倒: h( i, j ) = (i, src.rows - j)

    (3). 

图像左右颠倒: h(i,j) = ( src.cols - i, j )

    (4). 

同时执行b和c的操作: h(i,j) = ( src.cols - i, src.rows - j )



代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace cv;
/// Global variables
Mat src, dst;
Mat map_x, map_y;
char* remap_window = "Remap demo";
int ind = 0;
/// Function Headers
void update_map(void);
/**
* @function main
*/
int main(int argc, char** argv)
{
 /// Load the image
 src = imread("e:\\jay.jpg");
 /// Create dst, map_x and map_y with the same size as src:
 dst.create(src.size(), src.type());
 map_x.create(src.size(), CV_32FC1);
 map_y.create(src.size(), CV_32FC1);
 /// Create window
 namedWindow(remap_window, CV_WINDOW_AUTOSIZE);
 /// Loop
 while (true)
 {
  /// Each 1 sec. Press ESC to exit the program
  int c = waitKey(1000);
  if ((char)c == 27)
  {
   break;
  }
  /// Update map_x & map_y. Then apply remap
  update_map();
  remap(src, dst, map_x, map_y, CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
  /// Display results
  imshow(remap_window, dst);
 }
 return 0;
}
/**
* @function update_map
* @brief Fill the map_x and map_y matrices with 4 types of mappings
*/
void update_map(void)
{
 ind = ind % 4;
 for (int j = 0; j < src.rows; j++)
 {
  for (int i = 0; i < src.cols; i++)
  {
   switch (ind)
   {
   case 0:
    if (i > src.cols*0.25 && i < src.cols*0.75 && j > src.rows*0.25 && j < src.rows*0.75)
    {
     map_x.at<float>(j, i) = 2 * (i - src.cols*0.25) + 0.5;
     map_y.at<float>(j, i) = 2 * (j - src.rows*0.25) + 0.5;
    }
    else
    {
     map_x.at<float>(j, i) = 0;
     map_y.at<float>(j, i) = 0;
    }
    break;
   case 1:
    map_x.at<float>(j, i) = i;
    map_y.at<float>(j, i) = src.rows - j;
    break;
   case 2:
    map_x.at<float>(j, i) = src.cols - i;
    map_y.at<float>(j, i) = j;
    break;
   case 3:
    map_x.at<float>(j, i) = src.cols - i;
    map_y.at<float>(j, i) = src.rows - j;
    break;
   } // end of switch
  }
 }
 ind++;
}


13、仿射变换
    (1). 使用OpenCV函数 warpAffine 来实现一些简单的重映射.
    (2). 使用OpenCV函数 getRotationMatrix2D 来获得一个 2 \times 3 旋转矩阵

原理、步骤:
通过两组三点(分别对应)应用getAffineTransform函数求得仿射变换warp_mat(即 2 \times 3 矩阵)对src通过warpAffine应用求得的仿射变换warp_mat即可得出变换后的图像warp_dst,然后rot_mat =getRotationMatrix2D(center, angle, scale)获得旋转矩阵rot_mat ,再通过 warpAffine函数实现旋转,得到先变换后旋转的图像warp_rotate_dst。

代码:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace std;

/// 全局变量
char* source_window = "Source image";
char* warp_window = "Warp";
char* warp_rotate_window = "Warp + Rotate";

/** @function main */
int main(int argc, char** argv)
{
 Point2f srcTri[3];
 Point2f dstTri[3];

 Mat rot_mat(2, 3, CV_32FC1);
 Mat warp_mat(2, 3, CV_32FC1);
 Mat src, warp_dst, warp_rotate_dst;

 /// 加载源图像
 src = imread("e:\\jay.jpg");

 /// 设置目标图像的大小和类型与源图像一致
 warp_dst = Mat::zeros(src.rows, src.cols, src.type());

 /// 设置源图像和目标图像上的三组点以计算仿射变换
 srcTri[0] = Point2f(0, 0);
 srcTri[1] = Point2f(src.cols - 1, 0);
 srcTri[2] = Point2f(0, src.rows - 1);

 dstTri[0] = Point2f(src.cols*0.0, src.rows*0.33);
 dstTri[1] = Point2f(src.cols*0.85, src.rows*0.25);
 dstTri[2] = Point2f(src.cols*0.15, src.rows*0.7);

 /// 求得仿射变换
 warp_mat = getAffineTransform(srcTri, dstTri);

 /// 对源图像应用上面求得的仿射变换
 warpAffine(src, warp_dst, warp_mat, warp_dst.size());

 /** 对图像扭曲后再旋转 */

 /// 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵
 Point center = Point(warp_dst.cols / 2, warp_dst.rows / 2);
 double angle = -50.0;
 double scale = 0.6;

 /// 通过上面的旋转细节信息求得旋转矩阵
 rot_mat = getRotationMatrix2D(center, angle, scale);

 /// 旋转已扭曲图像
 warpAffine(warp_dst, warp_rotate_dst, rot_mat, warp_dst.size());

 /// 显示结果
 namedWindow(source_window, CV_WINDOW_AUTOSIZE);
 imshow(source_window, src);

 namedWindow(warp_window, CV_WINDOW_AUTOSIZE);
 imshow(warp_window, warp_dst);

 namedWindow(warp_rotate_window, CV_WINDOW_AUTOSIZE);
 imshow(warp_rotate_window, warp_rotate_dst);

 /// 等待用户按任意按键退出程序
 waitKey(0);

 return 0;
}


14、直方图均衡化
通过拉伸像素强度分布范围来增强图像对比度的一种方法。
 cvtColor(src, src, CV_BGR2GRAY);
 equalizeHist(src,dst);


15、在图像中寻找轮廓
    - 使用OpenCV函数 findContours
    - 使用OpenCV函数 drawContours


16、计算物体的凸包
    - 使用OpenCV函数 convexHull


17、创建包围轮廓的矩形和圆形边界框
    - 使用OpenCV函数 boundingRect 来计算包围轮廓的矩形框.
    - 使用OpenCV函数 minEnclosingCircle 来计算完全包围已有轮廓最小圆.


18、为轮廓创建可倾斜的边界框和椭圆
    - 使用OpenCV函数 minAreaRect
    - 使用OpenCV函数 fitEllipse


19、轮廓矩
    - 使用OpenCV函数 moments 计算图像所有的矩(最高到3阶)
    - 使用OpenCV函数 contourArea 来计算轮廓面积
    - 使用OpenCV函数 arcLength 来计算轮廓或曲线长度


***20、多边形测试
    - 使用OpenCV函数 pointPolygonTest


21、直方图计算
    - 如何使用OpenCV函数 split 将图像分割成单通道数组。
    - 如何使用OpenCV函数 calcHist 计算图像阵列的直方图。
    - 如何使用OpenCV函数 normalize 归一化数组。

直方图的一些具体细节:

    (1). dims: 需要统计的特征的数目, 在上例中, dims = 1 因为我们仅仅统计了灰度值(灰度图像)。
    (2). bins: 每个特征空间 子区段 的数目,在上例中, bins = 16
    (3). range: 每个特征空间的取值范围,在上例中, range = [0,255]


22、直方图对比
    - 如何使用OpenCV函数 compareHist 产生一个表达两个直方图的相似度的数值。
    - 如何使用不同的对比标准来对直方图进行比较。


23、反向投影
    - 使用OpenCV函数 calcBackProject 计算反向投影
    - 使用OpenCV函数 mixChannels 组合图像的不同通道


24、模板匹配
    - 使用OpenCV函数 matchTemplate 在模板块和输入图像之间寻找匹配,获得匹配结果图像
    - 使用OpenCV函数 minMaxLoc 在给定的矩阵中寻找最大和最小值(包括它们的位置).


25、为程序界面添加滑动条
    - 使用OpenCV函数 createTrackbar 在窗口中添加一个滑动条


26、OpenCV的视频输入和相似度测量
    - 如何打开和读取视频流
    - 两种检查相似度的方法:PSNR和SSIM


27、用OpenCV创建视频

你可能已经不满足于读取视频,还想要将你产生的一系列结果保存到一个新建的视频文件中。使用OpenCV中的 VideoWriter 类就可以简单的完成创建视频的工作。在接下来的教程中,我们将告诉你:

    - 如何用OpenCV创建一个视频文件
    - 用OpenCV能创建什么样的视频文件
    - 如何释放视频文件当中的某个颜色通道

0 0