描述:给一个BMP图像,两个二进制文件,二进制其实也是BMP图像,一模一样的,只是格式不一样,我们需要对二进制文件进行操作,在BMP图像上进行标记。具体是选取一个ROI区域在二进制文件中绘制直方图,选取前10%的直方图区域,在BMP图像文件进行映射和标记出来。
主文件:
#include<opencv2/opencv.hpp>
#include<iostream>
#include<fstream>
#include<quickopencv.h>
using namespace cv;
using namespace std;
Mat roi_select(Mat& image, Point sp, Point ep) {
int dx = ep.x - sp.x;
int dy = ep.y - sp.y;
Rect box(sp.x, sp.y, dx, dy);//ROI区域大小
Mat new_img = image(box);
QuickDemo qd;
Mat ROI_his = qd.histogram_grayImage(new_img);
namedWindow("ROI_his", WINDOW_FREERATIO);
imshow("ROI_his", ROI_his);
return new_img;
}
int main()
{
Mat src = imread("C:\\Users\\Administrator\\Documents\\WXWork\\1688850162194623\\Cache\\File\\2021-07\\009.bmp");
if (src.empty()) {
printf("could not load image...");
return -1;
}
namedWindow("input_image", WINDOW_AUTOSIZE);
imshow("input_image", src);
int height = src.rows;
int width = src.cols;
cv::Mat textureMat(height, width, CV_8UC3);
std::ifstream("C:\\Users\\Administrator\\Documents\\WXWork\\1688850162194623\\Cache\\File\\2021 - 07\\009.bmp",
std::ios::in | std::ios::binary).read((char*)textureMat.data,width * height * 3 * sizeof(uchar));
cv::Mat heightMat(height, width, CV_32FC1);
std::ifstream("C:\\Users\\Administrator\\Documents\\WXWork\\1688850162194623\\Cache\\File\\2021-07\\009_13",
std::ios::in | std::ios::binary).read((char*)heightMat.data, width * height * sizeof(float));
//namedWindow("src", WINDOW_FREERATIO);
//imshow("src", heightMat);
////选择ROI区域
//Rect rect = Rect(125, 1489, 309, 162);
//Scalar color = Scalar(0, 0, 255);
//rectangle(src, rect, color, 2, LINE_8);
//namedWindow("AOI_image", WINDOW_FREERATIO);
//imshow("AOI_image", src);
QuickDemo qd;
Mat hist = qd.histogram_grayImage(heightMat);
namedWindow("hist", WINDOW_FREERATIO);
imshow("hist", hist);
Mat new_heightMat = roi_select(heightMat, Point(0, 330), Point(950, 1500));
Mat new_src = roi_select(src, Point(0, 330), Point(950, 1500));
int h_height = new_heightMat.rows;
int h_width = new_heightMat.cols;
//获取满足前10%的像素坐标
for (int i = 0; i < h_height; i++)
{
for (int j = 0; j < h_width; j++)
{
if (new_heightMat.at<float>(i, j) < 25)
{
new_src.at<Vec3b>(i, j)[0] = 0;
new_src.at<Vec3b>(i, j)[1] = 0;
new_src.at<Vec3b>(i, j)[2] = 255;
}
}
}
namedWindow("output", WINDOW_FREERATIO);
imshow("output", new_src);
waitKey(0);
return 0;
}
l类中的cpp源文件:
Mat QuickDemo::histogram_grayImage(const Mat& image)
{
//定义求直方图的通道数目,从0开始索引
int channels[] = { 0 };
//定义直方图的在每一维上的大小,例如灰度图直方图的横坐标是图像的灰度值,就一维,bin的个数
//如果直方图图像横坐标bin个数为x,纵坐标bin个数为y,则channels[]={1,2}其直方图应该为三维的,Z轴是每个bin上统计的数目
const int histSize[] = { 256 };
//每一维bin的变化范围
float range[] = { 0,256 };
//所有bin的变化范围,个数跟channels应该跟channels一致
const float* ranges[] = { range };
//定义直方图,这里求的是直方图数据
Mat hist;
//opencv中计算直方图的函数,hist大小为256*1,每行存储的统计的该行对应的灰度值的个数
calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges, true, false);
//找出直方图统计的个数的最大值,用来作为直方图纵坐标的高
double maxValue = 0;
//找矩阵中最大最小值及对应索引的函数
minMaxLoc(hist, 0, &maxValue, 0, 0);
//最大值取整
int rows = cvRound(maxValue);
//定义直方图图像,直方图纵坐标的高作为行数,列数为256(灰度值的个数)
//因为是直方图的图像,所以以黑白两色为区分,白色为直方图的图像
Mat histImage = Mat::zeros(rows, 256, CV_8UC1);
//直方图图像表示
for (int i = 0; i < 256; i++)
{
//取每个bin的数目
int temp = (int)(hist.at<float>(i, 0));
//如果bin数目为0,则说明图像上没有该灰度值,则整列为黑色
//如果图像上有该灰度值,则将该列对应个数的像素设为白色
if (temp)
{
//由于图像坐标是以左上角为原点,所以要进行变换,使直方图图像以左下角为坐标原点
histImage.col(i).rowRange(Range(rows - temp, rows)) = 255;
}
}
//由于直方图图像列高可能很高,因此进行图像对列要进行对应的缩减,使直方图图像更直观
Mat resizeImage;
resize(histImage, resizeImage, Size(256, 256));
return resizeImage;
}
实现结果:
原图
二进制文件直方图、ROI区域直方图
ROI区域标定结果
测试文件链接: