图像识别10 图像直方图2
Posted 神马学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图像识别10 图像直方图2相关的知识,希望对你有一定的参考价值。
越往下写 ,越感觉自己的基础越薄弱。
这是图像直方图程序 笔记:
本身就是什么都不懂的小白,装什么,服了自己。
好了,开始,看程序时,突然有个问题--1.为什么有的函数有cv::,有时又不带?懵逼
查了网上答案,好像理解了。
OpenCV所有类及函数都放在CV 命名空间 里,所以使用这些类或者函数时需要cv::
如此例:
#include "opencv2/core/core.hpp"
...
cv::Mat H = cv::findHomography(points1, points2, CV_RANSAC, 5);
...
也可以使用 using namespace cv; 指令,之后使用这些类或者函数就可以省略cv::
如此例:
#include "opencv2/core/core.hpp"
using namespace cv;
...
Mat H = findHomography(points1, points2, CV_RANSAC, 5 );
...
2.system("color 1f");是什么意思啊 ?
c语言中的 system 就是调用dos命令。
color 1f 是用来设置Dos窗口颜色的; 前面的 1 设置窗口背景颜色,f 设置窗口字体颜色(前景颜色);这样的颜色值只有4位,依次是: 高亮,R, G, B 来分的;因此 1 是蓝色,F 是高亮白色。背景蓝色,字体高亮白色;
指定控制台输出的颜色属性
颜色属性由两个十六进制数字指定 -- 第一个为背景,第二个则为
前景。每个数字可以为以下任何值之一:
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 湖蓝色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色
3.mat和matnd的区别:
简单的说,Mat特指2维矩阵,MatND是多维矩阵(>=3维);
Mat对象提供了size()、channels()和depth()等方法分别获得图像的大小、通道数和数值类型。上面的例子中,图像img的宽为512个像素,高为393个像素,有3个通道(channels),即图像中的每个像素的颜色用三个数值表示。每个通道的数值类型(depth)的编号为0,0表示无符号8bit整数。
MatND对象使用size和step属性保存每个轴的长度和每个轴的字节偏移量,它们和NumPy数组的shape和strides属性类似。但是这两个属性都是长度固定为32的整数数组。
所以今天给大家一个解释更清楚的程序,并且能显示值
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
//首先肯定是读取图片,转换为灰度图并且在一个窗口上面显示
cv::Mat sourcePic = cv::imread("D:\\abc\\1.jpg", cv::IMREAD_GRAYSCALE);
cv::imshow("Source Picture", sourcePic);
//定义函数需要的一些变量
//图片数量nimages
int nimages = 1;
//通道数量,我们总是习惯用数组来表示,后面会讲原因
int channels[1] = { 0 };
//输出直方图
cv::Mat outputHist;
//维数
int dims = 1;
//存放每个维度直方图尺寸(bin数量)的数组histSize
int histSize[1] = { 256 };
//每一维数值的取值范围ranges
float hranges[2] = { 0, 255 };
//值范围的指针
const float *ranges[1] = { hranges };
//是否均匀
bool uni = true;
//是否累积
bool accum = false;
//计算图像的直方图
cv::calcHist(&sourcePic, nimages, channels, cv::Mat(), outputHist, dims, histSize, ranges, uni, accum);
//遍历每个箱子(bin)检验,这里的是在控制台输出的。
for (int i = 0; i < 256; i++)
std::cout << "bin/value:" << i << "=" << outputHist.at<float>(i) << std::endl;
//画出直方图
int scale = 1;
//直方图的图片
cv::Mat histPic(histSize[0] * scale, histSize[0], CV_8U, cv::Scalar(255)); \
//找到最大值和最小值
double maxValue = 0;
double minValue = 0;
cv::minMaxLoc(outputHist, &minValue, &maxValue, NULL, NULL);
//测试
std::cout << minValue << std::endl;
std::cout << maxValue << std::endl;
//纵坐标缩放比例
double rate = (histSize[0] / maxValue)*0.9;
for (int i = 0; i < histSize[0]; i++)
{
//得到每个i和箱子的值
float value = outputHist.at<float>(i);
//画直线
cv::line(histPic, cv::Point(i*scale, histSize[0]), cv::Point(i*scale, histSize[0] - value * rate), cv::Scalar(0));
}
cv::imshow("histgram", histPic);
cv::waitKey(0);
}
运行结果:
这样你就能看到每个占了多少。
根据峰值,再取阈值,再取二值化就可分割出前景和背景,甚至提取出你想要的目标。
再说下彩色图片,自然有了三个特征,那么维度便变为了3,依然是以上面那副图片作为例子,计算和画出三维的GBG直方图。
程序:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int main()
{
//首先肯定是彩色形式读取图片
cv::Mat sourcePic = cv::imread("D:\\abc\\1.jpg");
cv::imshow("Source Picture", sourcePic);
//定义函数需要的一些变量
//图片数量nimages
int nimages = 1;
//通道数量,我们总是习惯用数组来表示,后面会讲原因
int channels[3] = { 0,1,2 };
//输出直方图
cv::Mat outputHist_red, outputHist_green, outputHist_blue;
//维数
int dims = 1;
//存放每个维度直方图尺寸(bin数量)的数组histSize
int histSize[3] = { 256,256,256 };
//每一维数值的取值范围ranges
float hranges[2] = { 0, 255 };
//值范围的指针
const float *ranges[3] = { hranges,hranges,hranges };
//是否均匀
bool uni = true;
//是否累积
bool accum = false;
//计算图像的直方图(红色通道部分)
cv::calcHist(&sourcePic, nimages, &channels[0], cv::Mat(), outputHist_red, dims, &histSize[0], &ranges[0], uni, accum);
//计算图像的直方图(绿色通道部分)
cv::calcHist(&sourcePic, nimages, &channels[1], cv::Mat(), outputHist_green, dims, &histSize[1], &ranges[1], uni, accum);
//计算图像的直方图(蓝色通道部分)
cv::calcHist(&sourcePic, nimages, &channels[2], cv::Mat(), outputHist_blue, dims, &histSize[2], &ranges[2], uni, accum);
//遍历每个箱子(bin)检验,这里的是在控制台输出的。
//for (int i = 0; i < 256; i++)
//std::cout << "bin/value:" << i << "=" << outputHist_red.at<float>(i) << std::endl;
//画出直方图
int scale = 1;
//直方图的图片,因为尺寸是一样大的,所以就以histSize[0]来表示全部了.
cv::Mat histPic(histSize[0], histSize[0] * scale * 3, CV_8UC3, cv::Scalar(0, 0, 0));
//找到最大值和最小值,索引从0到2分别是红,绿,蓝
double maxValue[3] = { 0, 0, 0 };
double minValue[3] = { 0, 0, 0 };
cv::minMaxLoc(outputHist_red, &minValue[0], &maxValue[0], NULL, NULL);
cv::minMaxLoc(outputHist_green, &minValue[1], &maxValue[1], NULL, NULL);
cv::minMaxLoc(outputHist_blue, &minValue[2], &maxValue[2], NULL, NULL);
//测试
std::cout << minValue[0] << " " << minValue[1] << " " << minValue[2] << std::endl;
std::cout << maxValue[0] << " " << maxValue[1] << " " << maxValue[2] << std::endl;
//纵坐标缩放比例
double rate_red = (histSize[0] / maxValue[0])*0.9;
double rate_green = (histSize[0] / maxValue[1])*0.9;
double rate_blue = (histSize[0] / maxValue[2])*0.9;
for (int i = 0; i < histSize[0]; i++)
{
float value_red = outputHist_red.at<float>(i);
float value_green = outputHist_green.at<float>(i);
float value_blue = outputHist_blue.at<float>(i);
//分别画出直线
cv::line(histPic, cv::Point(i*scale, histSize[0]), cv::Point(i*scale, histSize[0] - value_red * rate_red), cv::Scalar(0, 0, 255));
cv::line(histPic, cv::Point((i + 256)*scale, histSize[0]), cv::Point((i + 256)*scale, histSize[0] - value_green * rate_green), cv::Scalar(0, 255, 0));
cv::line(histPic, cv::Point((i + 512)*scale, histSize[0]), cv::Point((i + 512)*scale, histSize[0] - value_blue * rate_blue), cv::Scalar(255, 0, 0));
}
cv::imshow("histgram", histPic);
cv::waitKey(0);
}
运行结果:
以上是关于图像识别10 图像直方图2的主要内容,如果未能解决你的问题,请参考以下文章