掩膜操作 提高图像对比度

掩膜操作 提高图像对比度

1.获取图像像素指针
CV_Assert(src.depth() == CV_8U);
Mat.ptr(int i=0) 获取像素矩阵的指针,i表示第几行,从0开始计数。
获得当前行指针const uchar* current=src.ptr(row);

2.像素范围处理
saturate_cast
这个函数的功能是确保RGB值的范围在0~255之间

3.图像的掩膜操作

掩膜操作是指根据掩膜矩阵(掩膜mask,也称作核kernel)重新计算图像中每个像素的值,实现图像对比度提高。

下面这个公式表示用5倍当前像素的值减去该像素上、下、左、右四个像素值和,得到的结果赋值给当前像素。
I ( i , j ) = 5 ∗ I ( i , j ) − [ I ( i − 1 , j ) + I ( i + 1 , j ) + I ( i , j − 1 ) + I ( i , j + 1 ) ] I(i,j)=5∗I(i,j)−[I(i−1,j)+I(i+1,j)+I(i,j−1)+I(i,j+1)] I(i,j)=5I(i,j)[I(i1,j)+I(i+1,j)+I(i,j1)+I(i,j+1)]
一个图像的通道数是N,就表明每个像素点处有N个数,一个a×b的N通道图像,其图像矩阵实际上是b行N×a列的数字矩阵。**所以要知道图像矩阵的实际的行列,cols(列数)=图像的cols*通道数,行数rows是一样的图像的rows。**计算图像的通道数用 channels()
!

框和图像左上角对齐,图像矩阵从(0,0)开始记,最左上角是(0,0),所以中心点一开始坐标是(1,1)。所以row是从1开始,到rows-1结束的,同理col应该也是,肯定到不了最后一个,这里对应的框都是对应图像像素点的,不是图像矩阵,所以是提前在cols中先将图像的cols-1并不是直接在图像矩阵cols上减一,那么对应的图像矩阵的col初始值并非对应图像cols为1,图像矩阵的cols是0,没意义。而是当图像的cols为2,此时图像矩阵的cols是通道值。可以把这个特殊值设出来为offsetx。
中间像素点和左边像素点对应的图像矩阵列数相差应该是通道数。

一般我们是不会在原图上做修改的,所以用const 来对current进行设定,const是一个C++语言的限定符,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。在此处是用其修饰指针的功能。
由于设定的current设定是const,因为不可以修改,故在原图像不能输出。所以我们设一个和src一样大的矩阵元素全是零dst且类型一致,利用指针将算出的像素放到dst中来输出掩膜后的图。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>

using namespace cv;

int main(int argc, char** argv)
{
	Mat src, dst;
	src = imread("D:/1.jpg");
	CV_Assert(src.depth() == CV_8U);
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image", src);


	int cols = (src.cols-1) *src.channels();
	int offsetx = src.channels();
	int rows = src.rows;
	dst = Mat::zeros(src.size(), src.type());

	for (int row = 1; row < (rows - 1); row++)
	{
		const uchar* previous = src.ptr<uchar>(row - 1);
		const uchar* current = src.ptr<uchar>(row);
		const uchar* next = src.ptr<uchar>(row + 1);
		uchar* output = dst.ptr<uchar>(row);
		
		for (int col = offsetx; col < (cols - 1); col++)
		{
			output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
			
		} 
	}

	namedWindow("contrast image demo", WINDOW_AUTOSIZE);
	imshow("contrast image demo", dst);

	waitKey(0);
	return 0;
}

4.使用opencv带有的API函数也可以实现
定义掩膜:
Mat kernel=(Mat_(3,3)<<0,-1,0,-1,5,-1,0,-1,0);
filter2D(src,dst,src.depth(),kernel);
其中src和dst是Mat类型变量,src.depth表示位图深度,有32,24,8等。例子中填scr.depth()表示和原图的位图深度一样,在你不知道是多少时,也可以选择填-1,就是暗示输出的位图深度和原图像相同,两个都可以,效果相同。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <math.h>

using namespace cv;

int main(int argc, char** argv)
{
	Mat src, dst;
	src = imread("D:/1.jpg");
	CV_Assert(src.depth() == CV_8U);
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input image", WINDOW_AUTOSIZE);
	imshow("input image", src);

	/*
	int cols = (src.cols-1) *src.channels();
	int offsetx = src.channels();
	int rows = src.rows;
	dst = Mat::zeros(src.size(), src.type());

	for (int row = 1; row < (rows - 1); row++)
	{
		const uchar* previous = src.ptr<uchar>(row - 1);
		const uchar* current = src.ptr<uchar>(row);
		const uchar* next = src.ptr<uchar>(row + 1);
		uchar* output = dst.ptr<uchar>(row);
		
		for (int col = offsetx; col < (cols - 1); col++)
		{
			output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
			
		} 
	}
	*/

	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	filter2D(src, dst, src.depth(), kernel);

	namedWindow("contrast image demo", WINDOW_AUTOSIZE);
	imshow("contrast image demo", dst);

	waitKey(0);
	return 0;
}

5.获取程序执行时间
getTickcount():返回从操作系统启动到当前所经的计时周期数。
getTickFrequency():返回每秒的计时周期数。
先获取一开始的执行时间,执行API 指令后,用新的执行时间减去一开始的执行时间t,再除以getTickFrequency(),就可以表示程序的执行时间。

double t = getTickCount();
	Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, 
									-1, 5, -1,
									 0, -1, 0);
	filter2D(src, dst, src.depth(), kernel);
	double timeconsume = (getTickCount() - t) / getTickFrequency();
	printf("time consume %.2f", timeconsume);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值