一.读图像、显示图像、保存图像。imread( );imshow( ); imwrite( ) 函数实现。
代码如下:
//图像的读取,保存,显示,二值化,灰度图
#include<iostream>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\imgproc\types_c.h>
using namespace std;
using namespace cv;
int main(
) {
Mat img, imgGray, result;
img = imread("D:\\opencv\\scy.jpg");
if (!img.data)
{
cout << "Please input image path" << endl;
return 0;
} imshow("原图", img);
cvtColor(img, imgGray, CV_BGR2GRAY);
imshow("灰度图", imgGray);//灰度图
blur(imgGray, imgGray, Size(3, 3));
threshold(imgGray, result, 100, 255, CV_THRESH_BINARY);//对图像进行二值化
imshow("二值化后的图", result);
imwrite("二值化的向日葵.jpg", result);//图片保存到文件夹下
cout << "图片已保存" << endl;
waitKey();
return 0;
}
运行结果:
注意内容:
1.其中图像内容被保存到程序所在的文件夹下,即:D:\\opencv\\scy.jpg路径下。
2. 使用标识符CV_BGR2GRAY必须引入头文件:
#include <opencv2\imgproc\types_c.h>
二.(1)图像平滑 Blur( ) ;
代码片段如下:
//blur的作用是对输入的图像src进行均值滤波后用dst输出
Mat src, dst;
src = imread("D:\\opencv\\scy.jpg");
if (!src.data)
{
return 0;
}
blur(src, dst, Size(3, 3));//Size(3,3)就表示3x3的核大小
imshow("原图", src);
imshow("3×3均值滤波图像输出", dst);
blur(src, dst, Size(8, 8));//Size(8,8)就表示8x8的核大小
imshow("8×8均值滤波图像输出", dst);
运行结果:
注意事项:
1.图片路径需要修改为自己的图片路径
2.核大小的值不同时,显示出的图像会有较大的区别,一般来说数值越大,图像越是迷糊。可从运行结果观察。
二(2)高斯平滑GaussianBlur();
代码如下:
#include <opencv2/opencv.hpp>
void example(const cv::Mat& image) {
cv::namedWindow("Example_in", cv::WINDOW_AUTOSIZE);
cv::namedWindow("Example_out", cv::WINDOW_AUTOSIZE);
cv::imshow("Example_in", image);
cv::Mat out;
cv::GaussianBlur(image, out, cv::Size(5, 5), 3, 3);
//cv::GaussianBlur(out, out, cv::Size(5,5), 3, 3);
cv::imshow("Example_out", out);
cv::waitKey(0);
}
int main() {
cv::Mat image = cv::imread("D:\\opencv\\scy.jpg");
example(image);
return 0;
}
运行结果:
注意事项:
1.可以对代码中cv::size(5,5)进行修改,但值得注意的是:该数值必须为奇数,当数值都为1时,原图像不发生改变,相应的随着数值的增大,模糊程度增加。
2.图片路径修改为自己的项目下图片的路径。
三.二值化、自适应二值化 threshold(); adaptiveThreshold() ;(主要是adaptiveThreshold() ;threshold();部分见一.)
代码如下:
//自适应阈值实现图像的二值化 adaptiveThreshold()
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/imgproc/types_c.h>
int main()
{
cv::Mat srcImage = cv::imread("D:\\opencv\\scy.jpg");
if (!srcImage.data)
return 1;
// 灰度转换
cv::Mat srcGray;
cv::cvtColor(srcImage, srcGray, CV_RGB2GRAY);//自适应阈值实现图像的二值化
//cv::imshow("srcGray", srcGray);
cv::Mat dstImage;
// 初始化自适应阈值参数
int blockSize = 5;
int constValue = 10;
const int maxVal = 255;
//以下是自适应阈值操作
int adaptiveMethod = 0;
int thresholdType = 1;
cv::adaptiveThreshold(srcGray, dstImage,
maxVal, adaptiveMethod,
thresholdType, blockSize,
constValue);
cv::imshow("dstImage", dstImage);
cv::waitKey(0);
return 0;
}
运行结果:
注意事项:
1.图片路径修改为自己项目下的图片文件的路径
四.标记、计算目标的形状特征参数: findContours() 每一个目标的面积、周长、长径、短径(最小外接矩形的长和宽,最小外接椭圆的长径、短径)
代码如下:
//标记、计算目标的形状特征参数:
//findContours()
//每一个目标的面积、周长、长径、短径(最小外接矩形的长和宽,最小外接椭圆的长径、短径)
#include <opencv2/opencv.hpp>
#include <iostream>
#include "windows.h"
#include <stdio.h>
#include <time.h>
#include <math.h>
//#include "My_ImageProssing_base.h"
#define WINDOW_NAME "【程序窗口】" //为窗口标题定义的宏
using namespace cv;
using namespace std;
RNG g_rng(12345);
int main()
{
//改变控制台字体颜色
system("color 04");
//读取图像
Mat src_image = imread("D:\\opencv\\scy1.jpg", 1);
//出错判断
if (!src_image.data)
{
cout << "src image load failed!" << endl;
return -1;
}
//显示原图
namedWindow("原图", WINDOW_NORMAL);
imshow("原图", src_image);
//高斯滤波去噪声
Mat blur_image;
GaussianBlur(src_image, blur_image, Size(3, 3), 0, 0);
imshow("GaussianBlur", blur_image);
//灰度变换与二值化
Mat gray_image, binary_image;
cvtColor(blur_image, gray_image, COLOR_BGR2GRAY);
threshold(gray_image, binary_image, 100, 255, THRESH_BINARY);
imshow("binary", binary_image);
//形态学闭操作(粘合断开的区域)
Mat morph_image;
Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
morphologyEx(binary_image, morph_image, MORPH_CLOSE, kernel, Point(-1, -1), 1);
imshow("morphology", morph_image);
//查找所有外轮廓
vector< vector<Point> > contours;
vector<Vec4i> hireachy;
findContours(binary_image, contours, hireachy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
//定义结果图
Mat result_image = Mat::zeros(src_image.size(), CV_8UC3);
//drawContours(result_image, contours, -1, Scalar(0, 0, 255), 1, 8, hireachy);//画出所有轮廓
//初始化周长、面积、圆形度、周径比
double len = 0, area = 0, roundness = 0, lenratio = 0;
float rectangularity;
//循环找出所有符合条件的轮廓
for (size_t t = 0; t < contours.size(); t++)
{
Scalar color = Scalar(g_rng.uniform(0, 255),
g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
//条件:过滤掉小的干扰轮廓
Rect rect = boundingRect(contours[t]); //垂直边界最小矩形
if (rect.width < 10)
continue;
//画出找到的轮廓
drawContours(result_image, contours, t, color, 1, 8, hireachy);
//绘制轮廓的最小外结矩形
RotatedRect minrect = minAreaRect(contours[t]); //最小外接矩形
int minrectmianji = minrect.size.height * minrect.size.width;
Point2f P[4]; //四个顶点坐标
minrect.points(P);
for (int j = 0; j <= 3; j++)
{
line(result_image, P[j], P[(j + 1) % 4], color, 1);
}
cout << "最小外接矩形尺寸" << minrect.size << endl;//最小外接矩形尺寸
cout << "最小外接矩形面积" << minrectmianji << endl;//最小外接矩形尺寸
//绘制轮廓的最小外结圆
Point2f center; float radius;
minEnclosingCircle(contours[t], center, radius); //最小外接圆
circle(result_image, center, radius, color, 1);
//计算面积、周长、圆形度、周径比
area = contourArea(contours[t]);//计算轮廓面积
len = arcLength(contours[t], true);//计算轮廓周长
roundness = (4 * CV_PI * area) / (len * len);//圆形度
if (minrectmianji == 0)rectangularity = 0;
else rectangularity = area / minrectmianji;
//周径比,这里的周即周长,径是指上面找到的轮廓最小外接矩形的长的一条边
lenratio = len / (minrect.size.height > minrect.size.width ? minrect.size.height : minrect.size.width);
//输出结果
cout << "轮廓" << t << ":" << endl;
cout << "周长:" << len << endl;
cout << "面积:" << area << endl;
cout << "圆形度:" << roundness << endl;
cout << "矩形度:" << rectangularity << endl;
cout << "周径比:" << lenratio << endl;
}
//显示结果
namedWindow("轮廓图", WINDOW_NORMAL);
imshow("轮廓图", result_image);
waitKey(0);
return 0;
}
运行结果:
注意事项:
1.实现该部分的内容时,最好采用的图片能够有明确的个数,易于功能的实现即目标的数量和大小轮廓的统计。
2.代码中存在自动过滤对于结果有影响的无关紧要的图形部分,因此在选取图像的时候还是要正确合理选择图像。
3.修改图片路径。
五.对测量得到的数据进行统计分析 统计每个参数范围内目标的个数,得到统计直方图。
代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat src = imread("D:/opencv/scy.jpg");
if (src.empty())
{
cout << "open no success!" << endl;
return -1;
}
imshow("原图", src);
vector<Mat> dst_num;//建立单通道数组
split(src, dst_num);//将多通道图片分解成单通道图片
int histsize = 256;//直方图分级数
float range[] = { 0, 256 };//像素范围
const float* histRange = { range };//范围指针
Mat b_hist, g_hist, r_hist;//建立分量直方图
//进行直方图提取
calcHist(&dst_num[0], 1, 0, Mat(), b_hist, 1, &histsize, &histRange, true, false);
calcHist(&dst_num[1], 1, 0, Mat(), g_hist, 1, &histsize, &histRange);
calcHist(&dst_num[2], 1, 0, Mat(), r_hist, 1, &histsize, &histRange);
//通过图片进行显示,直方图提取出来是单通道数组形式
int hist_w = 512;
int hist_h = 400;
int bin_w = hist_w / histsize;
Mat hist_image(hist_w, hist_h, CV_8UC3, Scalar(0, 0, 0));
normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX);
normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX);
normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX);
for (int i = 1; i < histsize; i++)
{
line(hist_image, Point((i - 1) * bin_w, hist_h - cvRound(b_hist.at<float>(i - 1))), Point((i)*bin_w, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2);
line(hist_image, Point((i - 1) * bin_w, hist_h - cvRound(g_hist.at<float>(i - 1))), Point((i)*bin_w, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2);
line(hist_image, Point((i - 1) * bin_w, hist_h - cvRound(r_hist.at<float>(i - 1))), Point((i)*bin_w, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2);
}
cout << b_hist.at<float>(25) << endl;
imshow("直方图", hist_image);
waitKey(0);
return 0;
}
运行结果:
注意事项:
1.该部分实现的是简单的RGB图像三通道简单直方图的显示。
2.对于上述我所使用的图像不利于个数的统计,因此数值可能存在误差。
3.更换图片路径为自己的图片路径。
1.该文章作为本人公选课结课报告,有些内容的代码来源于网络,时间已久,如有原创代码作者,请与我联系沟通。
2.作为一个小白,对于opencv的认知仅仅局限于一个狭隘的范围,如有做的不正确的地方,还请各位指正。
3.e-mail:songchengyang@stu.ouc.edu.cn