1.图像直方图
直方图简单来说就是图像中每个像素值的个数统计,比如说一副灰度图中像素值为0的有多少个,1的有多少个……直方图是一种分析图像的手段:
1.1.(cv :: calcHist)计算直方图
CV_EXPORTS void calcHist( const Mat* images, int nimages,
const int* channels, InputArray mask,
OutputArray hist, int dims, const int* histSize,
const float** ranges, bool uniform = true, bool accumulate = false );
- images:要计算的原图,以方括号的形式传入,如:[img]
- nimages:源图像的数目
- channels:维度通道序列,第一幅图像的通道标号从0~image[0].channels()-1。Image[0]表示图像数组中的第一幅图像,channels()表示该图像的通道数量。同理,图像阵列中的第二幅图像,通道标号从image[0].channerls()开始,到image[1].channels()-1为止;第三、四幅图像的通道标号顺序依此类推;也就是说图像阵列中的所有图像的通道根据图像排列顺序,排成一个通道队列。
- mask:可选择的mask。如果该矩阵不空的话,它必须是一个8-bit的矩阵,与images[i]同尺寸。在图像中,只有被mask覆盖的区域的像素才参与直方图统计。如果这个参数想用默认值,输入Mat()就可以了。
- hist:输出直方图, 它是一个稠密或稀疏矩阵,具有dims个维度;
- dims:直方图的维度,一定是正值, CV_MAX_DIMS(当前OpenCV版本是32个);
- histSize:数组,即histSize[i]表示第i个维度上bin的个数;这里的维度可以理解为通道。
- ranges:当uniform=true时,ranges是多个二元数组组成的数组;当uniform=false时,ranges是多元数组组成的数组。当在每个维度(或通道)上每个直方条等宽时,即uniform=true时,灰度值的有效统计范围的下界用L0表示,上界用UhistSize[i]-1表示,角标中的i表示第i个维度(或通道),上下界值可以表示为hrange[i]={L0, UhistSize[i]-1}, 在统计时, L0和UhistSize[i]-1不在统计范围内。而ranges={hrange[0], hrange[1], …… , hrange[dims]}。ranges的元素个数由参数dims决定。其中,L0表示在该通道上第0个直方条(bin)的下边界,UhistSize[i]-1表示最后一个直方条histSize[i]-1的上边界。在该维度上直方条的个数为histSize[i],如hrange[0]={L0, UhistSize[0]},hrange[1]={ L1, UhistSize[1]},hrange[2]={ L2,UhistSize[2]}, …… , hrange[dims]={ L0, UhistSize[0]}。
当uniform=false时,ranges中的每个元素ranges[i]都是一个多元数组,元素个数为histSize[i]+1,它们分别是:L0, U0=L1, U1= L2, …… ,UhistSize[i]-2 , LhistSize[i]-1 , UhistSize[i]-1。所以,ranges[i]={ L0 , L1, L2, …… , LhistSize[i]-1 ,UhistSize[i]-1} - uniform:标识,用于说明直方条bin是否是均匀等宽的。
- accumulate:累积标识。如果该项设置,当直方图重新分配时,直方图在开始清零。这个特征可以使你通过几幅图像,累积计算一个简单的直方图,或者及时更新直方图。
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
const int bins = 256;
Mat src;
const char* winTitle = “input image”;
void showHistogram();
void drawHistogram(Mat& image);
int main(int argc, char argv)
{
src = imread("…/data/test6.jpg");
if (src.empty())
{
printf(“Could not load image…\n”);
return 0;
}
cvtColor(src, src, COLOR_BGR2GRAY); // 转为灰度图
namedWindow(winTitle, WINDOW_AUTOSIZE);
imshow(winTitle, src);
drawHistogram(src);
waitKey(0);
return 0;
}
void drawHistogram(Mat& image)
{
//定义参数变量
const int channels[1] = {
0 };
const int bins[1] = {
256 };
float hranges[2] = {
0,255 };
const float ranges[1] = {
hranges };
int dims = image.channels();
if (dims == 3)
{
vector<Mat> bgr_plane;
split(src, bgr_plane);
Mat b_hist;
Mat g_hist;
Mat r_hist;
//计算Blue,Green,Red通道的直方图
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
//显示直方图
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
//归一化直方图数据
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
// 绘制直方图曲线
for (int i = 1; i < bins[0]; i++) {
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
// 显示直方图
namedWindow(“Histogram Demo”, WINDOW_AUTOSIZE);
imshow(“Histogram Demo”, histImage);
}
else {
Mat hist;
// 计算Blue, Green, Red通道的直方图
calcHist(&image, 1, 0, Mat(), hist, 1, bins, ranges);
// 显示直方图
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
// 归一化直方图数据
normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
// 绘制直方图曲线
for (int i = 1; i < bins[0]; i++) {
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
}
// 显示直方图
namedWindow(“Histogram Demo”, WINDOW_AUTOSIZE);
imshow(“Histogram Demo”, histImage);
}
}
void showHistogram() {
// 三通道分离
vector<Mat> bgr_plane;
split(src, bgr_plane);
// 定义参数变量
const int channels[1] = {
0 };
const int bins[1] = {
256 };
float hranges[2] = {
0,255 };
const float ranges[1] = {
hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist;
// 计算Blue, Green, Red通道的直方图
calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
// 显示直方图
int hist_w = 512;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / bins[0]);
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
// 归一化直方图数据
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
// 绘制直方图曲线
for (int i = 1; i < bins[0]; i++) {
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
line(histImage, Point(bin_w (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
}
// 显示直方图
namedWindow(“Histogram Demo”, WINDOW_AUTOSIZE);
imshow(“Histogram Demo”, histImage);
}
执行结果:
1.2.(cv :: equalizeHist)直方图均衡化
void equalizeHist(InputArray src, OutputArray dst);
- src:输入图像,即源图像,填 Mat 类的对象即可,但需要为 8 位单通道的图像。
- dst:输出结果,需要和源图像有一样的尺寸和类型。
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char argv)
{
Mat src = imread(“E:…/data/test3.jpg”);
if (src.empty())
{
printf(“Could not load image…\n”);
return -1;
}
namedWindow(“input”, WINDOW_AUTOSIZE);
Mat gray, dst;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow(“input”, gray);
equalizeHist(gray, dst);
imshow(“eq”, dst);
<span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
执行结果:
1.3.均衡化后图片的直方图:
int main(int argc, char** argv)
{
src = imread("../data/test6.jpg");
if (src.empty())
{
printf("Could not load image..\n");
return 0;
}
cvtColor(src, src, COLOR_BGR2GRAY); // 转为灰度图
namedWindow(winTitle, WINDOW_AUTOSIZE);
//imshow(winTitle, src);
Mat gray, dst;
equalizeHist(src, dst);
imshow("equalizeHist image", dst);
drawHistogram(dst);
waitKey(0);
return 0;
}
1.4.图像直方图比较
图像直方图比较,就是比较两幅图像的直方图数据,比较两组数据的相似性,从而得到两幅图像之间的相似程度,直方图比较在早期的CBIR(基于内容的图像检索Content-based image retrieval)是较常应用的技术手段,通常结合边缘处理、词袋模型等技术一起使用。
词袋模型(英语:Bag-of-words model)是个在自然语言处理和信息检索(IR)下被简化的表达模型。此模型下,一段文本(比如一个句子或是一个文档)可以用一个装着这些词的袋子来表示,这种表示方式不考虑文法以及词的顺序。最近词袋模型也被应用在计算机视觉领域。
词袋模型被广泛应用在文件分类,词出现的频率可以用来当作训练分类器的特征。
double compareHist(InputArray H1, InputArray H2, int method);
- H1,H2:是要进行比较的直方图。
- method:比较方法。有如下选择:
#include<opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char argv)
{
//load the image
Mat src1 = imread("…/data/test3.jpg");
Mat src2 = imread("…/data/test6.jpg");
Mat src3 = imread("…/data/test2.jpg");
Mat src4 = imread("…/data/test5.jpg");
//show the image
imshow(“input1”, src1);
imshow(“input2”, src2);
imshow(“input3”, src3);
imshow(“input4”, src4);
//convert hte HSV to BGR
Mat hsv1, hsv2, hsv3, hsv4;
cvtColor(src1, hsv1, COLOR_BGR2HSV);
cvtColor(src2, hsv2, COLOR_BGR2HSV);
cvtColor(src3, hsv3, COLOR_BGR2HSV);
cvtColor(src4, hsv4, COLOR_BGR2HSV);
//calculate the hist
int h_bins = 60;
int s_bins = 64;
int histSize[] = {
h_bins,s_bins };
float h_ranges[] = {
0,180 };
float s_ranges[] = {
0,255 };
const float* ranges[] = {
h_ranges,s_ranges };
int channels[] = {
0,1 };
Mat hist1, hist2, hist3, hist4;
calcHist(&hsv1, 1, channels, Mat(), hist1, 2, histSize, ranges, true, false);
calcHist(&hsv2, 1, channels, Mat(), hist2, 2, histSize, ranges, true, false);
calcHist(&hsv3, 1, channels, Mat(), hist3, 2, histSize, ranges, true, false);
calcHist(&hsv4, 1, channels, Mat(), hist4, 2, histSize, ranges, true, false);
<span class="token function">normalize</span><span class="token punctuation">(</span>hist1<span class="token punctuation">,</span> hist1<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> NORM_MINMAX<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Mat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">normalize</span><span class="token punctuation">(</span>hist2<span class="token punctuation">,</span> hist2<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> NORM_MINMAX<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Mat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">normalize</span><span class="token punctuation">(</span>hist3<span class="token punctuation">,</span> hist3<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> NORM_MINMAX<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Mat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">normalize</span><span class="token punctuation">(</span>hist4<span class="token punctuation">,</span> hist4<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> NORM_MINMAX<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token function">Mat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">4</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">int</span> compare_method <span class="token operator">=</span> i<span class="token punctuation">;</span>
<span class="token keyword">double</span> src1_src2 <span class="token operator">=</span> <span class="token function">compareHist</span><span class="token punctuation">(</span>hist1<span class="token punctuation">,</span> hist2<span class="token punctuation">,</span> compare_method<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">double</span> src3_src4 <span class="token operator">=</span> <span class="token function">compareHist</span><span class="token punctuation">(</span>hist3<span class="token punctuation">,</span> hist4<span class="token punctuation">,</span> compare_method<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">printf</span><span class="token punctuation">(</span><span class="token string">" Method [%d]: src1_src2: %f, src3_src4: %f,\n"</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> src1_src2<span class="token punctuation">,</span> src3_src4<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
2.后投影
2.1.(cv :: mixChannels )通道复制
mixChannels 主要就是把输入的图像(或图像集)的某些通道拆分复制给对应的输出图像(或图像集)的某些通道中,其中的对应关系由 fromTo 参数制定。
void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_to npairs);
- src,输入的图像或图像集,需要有相同的尺寸和深度。
- nsrcs,输入图像个数。
- dst,输出图像,所有图像必须被初始化,且大小和深度必须与 src[0] 相同。
- ndsts,输出图像个数。
- fromTo,输入图像通道与输出图像通道的对应关系。
- npairs,fromTo 的索引数,即有几个 fromTo。
2.2.(cv :: createTrackbar)创建轨迹条
创建一个可以调整数值的轨迹条,并将轨迹条附加到指定的窗口上,使用起来很方便。
int createTrackbar(const String& trackbarname, const String& winname,
int* value, int count,
TrackbarCallback onChange = 0,
void* userdata = 0);
- trackbarname:表示轨迹条的名字,用来代表我们创建的轨迹条。
- winname:填窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow()创建窗口时填的某一个窗口名。
- value:一个指向整型的指针,表示滑块的位置。并且在创建时,滑块的初始位置就是该变量当前的值。
- count:表示滑块可以达到的最大位置的值。PS:滑块最小的位置的值始终为0。
- onChange:首先注意他有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void
XXXX(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化。 - userdata:他也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat hue;
int bins = 25;
void Hist_and_Backproj(int, void*);
int main(int argc, char* argv[])
{
Mat src = imread("…/data/test6.jpg");
if (src.empty())
{
cout << “Could not open or find the image!\n” << endl;
cout << “Usage: " << argv[0] << " <Input image>” << endl;
return -1;
}
Mat hsv<span class="token punctuation">;</span>
<span class="token function">cvtColor</span><span class="token punctuation">(</span>src<span class="token punctuation">,</span> hsv<span class="token punctuation">,</span> COLOR_BGR2HSV<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//! [Use only the Hue value]</span>
hue<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>hsv<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> hsv<span class="token punctuation">.</span><span class="token function">depth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> ch<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">{<!-- --></span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token function">mixChannels</span><span class="token punctuation">(</span><span class="token operator">&</span>hsv<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token operator">&</span>hue<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> ch<span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//通道复制 </span>
<span class="token comment">//! [Create Trackbar to enter the number of bins]</span>
<span class="token keyword">const</span> <span class="token keyword">char</span><span class="token operator">*</span> window_image <span class="token operator">=</span> <span class="token string">"Source image"</span><span class="token punctuation">;</span>
<span class="token function">namedWindow</span><span class="token punctuation">(</span>window_image<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">createTrackbar</span><span class="token punctuation">(</span><span class="token string">"* Hue bins: "</span><span class="token punctuation">,</span> window_image<span class="token punctuation">,</span> <span class="token operator">&</span>bins<span class="token punctuation">,</span> <span class="token number">180</span><span class="token punctuation">,</span> Hist_and_Backproj<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">Hist_and_Backproj</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">imshow</span><span class="token punctuation">(</span>window_image<span class="token punctuation">,</span> src<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
void Hist_and_Backproj(int, void)
{
int histSize = MAX(bins, 2);
float hue_range[] = {
0, 180 };
const float ranges = {
hue_range };
//获取直方图并进行归一化
Mat hist;
calcHist(&hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false);
normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat());
//得到投影
Mat backproj;
calcBackProject(&hue, 1, 0, hist, backproj, &ranges, 1, true);
<span class="token comment">//画出backproj</span>
<span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"BackProj"</span><span class="token punctuation">,</span> backproj<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//画柱状图</span>
<span class="token keyword">int</span> w <span class="token operator">=</span> <span class="token number">400</span><span class="token punctuation">,</span> h <span class="token operator">=</span> <span class="token number">400</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> bin_w <span class="token operator">=</span> <span class="token function">cvRound</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">double</span><span class="token punctuation">)</span>w <span class="token operator">/</span> histSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
Mat histImg <span class="token operator">=</span> Mat<span class="token operator">::</span><span class="token function">zeros</span><span class="token punctuation">(</span>h<span class="token punctuation">,</span> w<span class="token punctuation">,</span> CV_8UC3<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> bins<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token function">rectangle</span><span class="token punctuation">(</span>histImg<span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span>i <span class="token operator">*</span> bin_w<span class="token punctuation">,</span> h<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">Point</span><span class="token punctuation">(</span><span class="token punctuation">(</span>i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> bin_w<span class="token punctuation">,</span> h <span class="token operator">-</span> <span class="token function">cvRound</span><span class="token punctuation">(</span>hist<span class="token punctuation">.</span>at<span class="token operator"><</span><span class="token keyword">float</span><span class="token operator">></span><span class="token punctuation">(</span>i<span class="token punctuation">)</span> <span class="token operator">*</span> h <span class="token operator">/</span> <span class="token number">255.0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token function">Scalar</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">,</span> FILLED<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"Histogram"</span><span class="token punctuation">,</span> histImg<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
执行结果:
3.数字识别
CV_EXPORTS_W Rect boundingRect( InputArray array );
3.1.简单数字识别
#define _CRT_SECURE_NO_WARNINGS
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
class myRect
{
public:
myRect() {
}
~myRect() {
}
myRect(Rect& temp) :myRc(temp) {
}
//比较矩形左上角的横坐标,以便排序
bool operator<(myRect& rect)
{
if (this->myRc.x < rect.myRc.x)
{
return true;
}
else
{
return false;
}
}
//重载赋值运算符
myRect operator=(myRect& rect)
{
this->myRc = rect.myRc;
return *this;
}
//获取矩形
Rect getRect()
{
return myRc;
}
private:
Rect myRc;//存放矩形
};
//求图片的像素和
int getPiexSum(Mat& image)
{
int sum = 0;
for (int i = 0; i < image.cols; i++)
{
for (int j = 0; j < image.rows; j++)
{
sum += image.at<uchar>(j, i);
}
}
return sum;
}
/主函数/
int main()
{
//输入要识别的图片,并显示
Mat srcImage = imread("./image/number3.jpg");
imshow(“原图”, srcImage);
//对图像进行处理,转化为灰度图然后再转为二值图
Mat grayImage;
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
Mat binImage;
//若为黑底白字则选择CV_THRESH_BINARY即可
threshold(grayImage, binImage, 100, 255, THRESH_BINARY_INV);
//threshold(grayImage, binImage, 100, 255, THRESH_BINARY);
<span class="token comment">//寻找轮廓,必须指定为寻找外部轮廓,不然一个数字可能有多个轮廓组成,比如4,6,8,9等数字</span>
Mat conImage <span class="token operator">=</span> Mat<span class="token operator">::</span><span class="token function">zeros</span><span class="token punctuation">(</span>binImage<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> binImage<span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vector<span class="token operator"><</span>vector<span class="token operator"><</span>Point<span class="token operator">>></span> contours<span class="token punctuation">;</span>
vector<span class="token operator"><</span>Vec4i<span class="token operator">></span> hierarchy<span class="token punctuation">;</span>
<span class="token comment">//指定CV_RETR_EXTERNAL寻找数字的外轮廓</span>
<span class="token function">findContours</span><span class="token punctuation">(</span>binImage<span class="token punctuation">,</span> contours<span class="token punctuation">,</span> hierarchy<span class="token punctuation">,</span> RETR_EXTERNAL<span class="token punctuation">,</span> CHAIN_APPROX_NONE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//绘制轮廓</span>
<span class="token function">drawContours</span><span class="token punctuation">(</span>conImage<span class="token punctuation">,</span> contours<span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">imshow</span><span class="token punctuation">(</span><span class="token string">"轮廓"</span><span class="token punctuation">,</span> conImage<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//将每个数字,分离开,保存到容器中</span>
vector<span class="token operator"><</span>myRect<span class="token operator">></span> sort_rect<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> contours<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token comment">//boundingRect返回轮廓的外接矩阵</span>
Rect tempRect <span class="token operator">=</span> <span class="token function">boundingRect</span><span class="token punctuation">(</span>contours<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
sort_rect<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>tempRect<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//对矩形进行排序,因为轮廓的顺序不一定是数字真正的顺序</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> sort_rect<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> i <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> j <span class="token operator"><</span> sort_rect<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>sort_rect<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator"><</span> sort_rect<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
myRect temp <span class="token operator">=</span> sort_rect<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span>
sort_rect<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> sort_rect<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
sort_rect<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> temp<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">/*加载模板,若没有则需自己新建一个*/</span>
<span class="token comment">//新建,运行一次就好,不过制作模板的材料为0-9十个数字的图像</span>
<span class="token comment">//for (int i = 0; i < 10; i++)</span>
<span class="token comment">//{<!-- --></span>
<span class="token comment">// Mat ROI = conImage(sort_rect[i].getRect());</span>
<span class="token comment">// Mat dstROI;</span>
<span class="token comment">// resize(ROI, dstROI, Size(40, 50),0, 0, INTER_NEAREST);</span>
<span class="token comment">// char name[64];</span>
<span class="token comment">// sprintf(name, "./image/number2/%d.jpg", i+1);</span>
<span class="token comment">// imwrite(name, dstROI);</span>
<span class="token comment">//}</span>
<span class="token comment">//加载模板</span>
vector<span class="token operator"><</span>Mat<span class="token operator">></span> myTemplate<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token keyword">char</span> name<span class="token punctuation">[</span><span class="token number">64</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token function">sprintf</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token string">"./image/number2/%d.jpg"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span>
Mat temp <span class="token operator">=</span> <span class="token function">imread</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
myTemplate<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>temp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//按顺序取出和分割数字</span>
vector<span class="token operator"><</span>Mat<span class="token operator">></span> myROI<span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> sort_rect<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
Mat ROI<span class="token punctuation">;</span>
ROI <span class="token operator">=</span> <span class="token function">conImage</span><span class="token punctuation">(</span>sort_rect<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">getRect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Mat dstROI <span class="token operator">=</span> Mat<span class="token operator">::</span><span class="token function">zeros</span><span class="token punctuation">(</span>myTemplate<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> myTemplate<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">resize</span><span class="token punctuation">(</span>ROI<span class="token punctuation">,</span> dstROI<span class="token punctuation">,</span> myTemplate<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> INTER_NEAREST<span class="token punctuation">)</span><span class="token punctuation">;</span>
myROI<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>dstROI<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//进行比较,将图片与模板相减,然后求全部像素和,和最小表示越相似,进而完成匹配</span>
vector<span class="token operator"><</span><span class="token keyword">int</span><span class="token operator">></span> seq<span class="token punctuation">;</span><span class="token comment">//顺序存放识别结果</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> myROI<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
Mat subImage<span class="token punctuation">;</span>
<span class="token keyword">int</span> sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> min <span class="token operator">=</span> <span class="token number">100000</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> min_seq <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token comment">//记录最小的和对应的数字</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> j <span class="token operator"><</span> <span class="token number">10</span><span class="token punctuation">;</span> j<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
<span class="token comment">//计算两个图片的差值</span>
<span class="token function">absdiff</span><span class="token punctuation">(</span>myROI<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> myTemplate<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">,</span> subImage<span class="token punctuation">)</span><span class="token punctuation">;</span>
sum <span class="token operator">=</span> <span class="token function">getPiexSum</span><span class="token punctuation">(</span>subImage<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>sum <span class="token operator"><</span> min<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
min <span class="token operator">=</span> sum<span class="token punctuation">;</span>
min_seq <span class="token operator">=</span> j<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
seq<span class="token punctuation">.</span><span class="token function">push_back</span><span class="token punctuation">(</span>min_seq<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//输出结果</span>
cout <span class="token operator"><<</span> <span class="token string">"识别结果为:"</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> seq<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
cout <span class="token operator"><<</span> seq<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
cout <span class="token operator"><<</span> endl<span class="token punctuation">;</span>
<span class="token function">waitKey</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">system</span><span class="token punctuation">(</span><span class="token string">"pause"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
执行结果:
完整源码:https://download.csdn.net/download/qq_35831134/19748532