2. 矩阵的掩膜操作 (OpenCV基础课程视频学习)

课程视频链接:https://www.bilibili.com/video/av29600072?p=3

内容

  • 掩膜操作解释
  • 获取图像像素指针
  • 完整代码

1. 掩膜操作解释

  • 掩膜操作可实现图像对比度调整
  • 矩阵的掩膜操作是根据掩膜来重新计算每个像素的像素值,掩膜(mask 也被称为 Kernel)

例如

在这里插入图片描述

  • 红色是中心像素,从上到下,从左到右对每个像素都做同样的处理操作,得到最终结果就是对比度提高之后的输出图像
I(i,j) = 5 * I(i,j) - [I(i-1,j) + I(i+1,j) + I(i,j-1) + I(i,j+1)]

通过公式可知,如果选择的这个中心点比周围的点暗,那就让它更暗,同理,如果比周围亮,那就让它更亮。当把这个操作扩展到整个图像之后,图像之间的亮暗差距会变得更大,也就是对比度会更大。又因为一个图像的边缘点没有四周进行对比,不能使用公式,所以在写程序时,循环变量即图像的行数和列数要从 1 开始,去掉最外圈像素没有办法进行比较的点。

2. 获取图像像素指针

2.1 CV_Assert
CV_Assert(myImage.depth() == CV_8U);
  • Mat.ptr(int i=0) 获取像素矩阵的指针,索引 i 表示第几行,从 0 开始计行数。“ptr” 是指针的意思。“uchar” 是一个字节。
  • 获得当前行指针
const uchar* current = myImage.ptr<uchar>(row);
  • 获取当前像素点 P(row, col) 的像素值 p(row, col) = current[col];
2.2 saturate_cast 像素范围处理
  • 像素范围处理 saturate_cast,这个函数的功能是确保 RGB 值的范围在 0~255 之间。
语句作用
saturate_cast (-100)返回 0
saturate_cast (288)返回255
saturate_cast (100)返回100
2.3 获取图像长度和宽度

图像的长度和宽度即图像的行数 rows 和列数 cols ,这些都是 Mat 对象的属性,可直接通过 Mat 对象访问。

image.rows   // 图像行数
image.cols   // 图像列数

注意:以上方式与其说是计算行数和列数不如说是计算图像的行数和列通道数,而三通道的图像存储第一行为 B0G0R0B1G1R1……,不是 B0B1B2……,所以在计算 BGR 三通道图像的列数时要 *3,即乘以图像的通道数:

int cols = image.cols * image.channels();
2.4 掩膜操作

有两种实现掩膜操作的方法

2.4.1 方法一

使用循环,手动编写中心元素的计算公式,然后遍历整幅图像的所有中心点。

完整代码

#include <opencv.hpp>

#include <iostream>

int main(int argc, char** argv)
{
	cv::String imageName = "HappyFish.jpg";

	if (argc > 1)
		imageName = argv[1];

	cv::Mat image = cv::imread(cv::samples::findFile(imageName), cv::IMREAD_COLOR);

	cv::namedWindow("Display", cv::WINDOW_AUTOSIZE);

	if (image.empty())
	{
		std::cout << "No image" << std::endl;
		return -1;
	}

	cv::imshow("Display", image);

	cv::Mat dst;
	int cols = (image.cols - 1) * image.channels();
	int offsetx = image.channels();
	int rows = image.rows;

	dst = cv::Mat::zeros(image.size(), image.type());

	for (int row = 1; row < rows - 1; row++)
	{
		const uchar* previous = image.ptr<uchar>(row - 1);
		const uchar* current = image.ptr<uchar>(row);
		const uchar* next = image.ptr<uchar>(row + 1);
		uchar* output = dst.ptr<uchar>(row);

		for (int col = 1; col < cols - 1; col++)
		{
			output[col] = cv::saturate_cast<uchar>(5 * current[col] - (previous[col] + next[col] + current[col - offsetx] + current[col + offsetx]));
		}
	}

	cv::namedWindow("Transform", cv::WINDOW_AUTOSIZE);
	imshow("Transform", dst);
	
	cv::waitKey(0); 

	return 0;

}

结果
在这里插入图片描述

2.4.2 方法二

先建立一个掩膜模板,使用 filter2D 语句。

filter2D

  • 定义掩膜:
cv::Mat mask = (cv::Mat_<char>(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 等。若 src.depth() 赋值为 -1 时,意味着图像深度与原图一致。

完整代码

#include <opencv.hpp>

#include <iostream>

int main(int argc, char** argv)
{
	cv::String imageName = "HappyFish.jpg";

	if (argc > 1)
		imageName = argv[1];

	cv::Mat image = cv::imread(cv::samples::findFile(imageName), cv::IMREAD_COLOR);

	cv::namedWindow("Display", cv::WINDOW_AUTOSIZE);

	if (image.empty())
	{
		std::cout << "No image" << std::endl;
		return -1;
	}

	cv::imshow("Display", image);

	cv::Mat dst;

	cv::Mat mask = (cv::Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	cv::filter2D(image, dst, image.depth(), mask);

	cv::namedWindow("Transform", cv::WINDOW_AUTOSIZE);
	imshow("Transform", dst);
	
	cv::waitKey(0); 

	return 0;

}

结果
在这里插入图片描述

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值