图像映射---实现局部ROI区域通过直方图的范围进行图像标定

本文介绍如何使用OpenCV处理BMP图像和二进制文件,通过选取ROI区域并绘制直方图,筛选前10%的数据,将筛选结果映射到原始图像上实现标记。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述:给一个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区域标定结果

测试文件链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI炮灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值