OpenCV4.9关于矩阵上的掩码操作

 返回:OpenCV系列文章目录(持续更新中......)

上一篇:如何使用OpenCV扫描图像、查找表和时间测量

下一篇:OpenCV4.9的是如何进行图像操作 

引言:

矩阵上的掩码操作非常简单。这个想法是,我们根据掩码矩阵(也称为内核)重新计算图像中每个像素的值。此蒙版包含的值将调整相邻像素(和当前像素)对新像素值的影响程度。从数学的角度来看,我们用指定的值做一个加权平均值。

测试用例

考虑图像对比度增强方法的问题。对图像的每个像素基本上应用以下公式:

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)∗M,where M=i∖j−10+1−10−100−15−1+10−10

第一种表示法是使用公式,而第二种表示法是第一种表示法的压缩版本,使用蒙版。使用蒙版的方法是将蒙版矩阵的中心(以大写字母表示,由零零索引表示)放在要计算的像素上,并将像素值乘以重叠的矩阵值相加。这是一回事,但是在大型矩阵的情况下,后一种符号更容易查看。

代码

C++

您可以从此处下载此源代码,或查看 OpenCV 源代码库示例目录  samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp.

​#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
static void help(char* progName)
{
cout << endl
<< "This program shows how to filter images with mask: the write it yourself and the"
<< "filter2d way. " << endl
<< "Usage:" << endl
<< progName << " [image_path -- default lena.jpg] [G -- grayscale] " << endl << endl;
}
void Sharpen(const Mat& myImage,Mat& Result);
int main( int argc, char* argv[])
{
help(argv[0]);
const char* filename = argc >=2 ? argv[1] : "lena.jpg";
Mat src, dst0, dst1;
if (argc >= 3 && !strcmp("G", argv[2]))
src = imread( samples::findFile( filename ), IMREAD_GRAYSCALE);
else
src = imread( samples::findFile( filename ), IMREAD_COLOR);
if (src.empty())
{
cerr << "Can't open image [" << filename << "]" << endl;
return EXIT_FAILURE;
}
namedWindow("Input", WINDOW_AUTOSIZE);
namedWindow("Output", WINDOW_AUTOSIZE);
imshow( "Input", src );
double t = (double)getTickCount();
Sharpen( src, dst0 );
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Hand written function time passed in seconds: " << t << endl;
imshow( "Output", dst0 );
waitKey();
Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,
-1, 5, -1,
0, -1, 0);
t = (double)getTickCount();
filter2D( src, dst1, src.depth(), kernel );
t = ((double)getTickCount() - t)/getTickFrequency();
cout << "Built-in filter2D time passed in seconds: " << t << endl;
imshow( "Output", dst1 );
waitKey();
return EXIT_SUCCESS;
}
void Sharpen(const Mat& myImage,Mat& Result)
{
CV_Assert(myImage.depth() == CV_8U); // accept only uchar images
const int nChannels = myImage.channels();
Result.create(myImage.size(),myImage.type());
for(int j = 1 ; j < myImage.rows-1; ++j)
{
const uchar* previous = myImage.ptr<uchar>(j - 1);
const uchar* current = myImage.ptr<uchar>(j );
const uchar* next = myImage.ptr<uchar>(j + 1);
uchar* output = Result.ptr<uchar>(j);
for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i)
{
output[i] = saturate_cast<uchar>(5*current[i]
-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
}
}
Result.row(0).setTo(Scalar(0));
Result.row(Result.rows-1).setTo(Scalar(0));
Result.col(0).setTo(Scalar(0));
Result.col(Result.cols-1).setTo(Scalar(0));
}

Java代码:samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java.

import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class MatMaskOperationsRun {public void run(String[] args) {String filename = "../data/lena.jpg";int img_codec = Imgcodecs.IMREAD_COLOR;if (args.length != 0) {filename = args[0];if (args.length >= 2 && args[1].equals("G"))img_codec = Imgcodecs.IMREAD_GRAYSCALE;}Mat src = Imgcodecs.imread(filename, img_codec);if (src.empty()) {System.out.println("Can't open image [" + filename + "]");System.out.println("Program Arguments: [image_path -- default ../data/lena.jpg] [G -- grayscale]");System.exit(-1);}HighGui.namedWindow("Input", HighGui.WINDOW_AUTOSIZE);HighGui.namedWindow("Output", HighGui.WINDOW_AUTOSIZE);HighGui.imshow( "Input", src );double t = System.currentTimeMillis();Mat dst0 = sharpen(src, new Mat());t = ((double) System.currentTimeMillis() - t) / 1000;System.out.println("Hand written function time passed in seconds: " + t);HighGui.imshow( "Output", dst0 );HighGui.moveWindow("Output", 400, 400);HighGui.waitKey();Mat kern = new Mat(3, 3, CvType.CV_8S);int row = 0, col = 0;kern.put(row, col, 0, -1, 0, -1, 5, -1, 0, -1, 0);t = System.currentTimeMillis();Mat dst1 = new Mat();Imgproc.filter2D(src, dst1, src.depth(), kern);t = ((double) System.currentTimeMillis() - t) / 1000;System.out.println("Built-in filter2D time passed in seconds: " + t);HighGui.imshow( "Output", dst1 );HighGui.waitKey();System.exit(0);}public static double saturate(double x) {return x > 255.0 ? 255.0 : (x < 0.0 ? 0.0 : x);}public Mat sharpen(Mat myImage, Mat Result) {myImage.convertTo(myImage, CvType.CV_8U);int nChannels = myImage.channels();Result.create(myImage.size(), myImage.type());for (int j = 1; j < myImage.rows() - 1; ++j) {for (int i = 1; i < myImage.cols() - 1; ++i) {double sum[] = new double[nChannels];for (int k = 0; k < nChannels; ++k) {double top = -myImage.get(j - 1, i)[k];double bottom = -myImage.get(j + 1, i)[k];double center = (5 * myImage.get(j, i)[k]);double left = -myImage.get(j, i - 1)[k];double right = -myImage.get(j, i + 1)[k];sum[k] = saturate(top + bottom + center + left + right);}Result.put(j, i, sum);}}Result.row(0).setTo(new Scalar(0));Result.row(Result.rows() - 1).setTo(new Scalar(0));Result.col(0).setTo(new Scalar(0));Result.col(Result.cols() - 1).setTo(new Scalar(0));return Result;}
}
public class MatMaskOperations {public static void main(String[] args) {// Load the native library.System.loadLibrary(Core.NATIVE_LIBRARY_NAME);new MatMaskOperationsRun().run(args);}
}

Python代码:

samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py.

from __future__ import print_function
import sys
import time
import numpy as np
import cv2 as cv
def is_grayscale(my_image):return len(my_image.shape) < 3
def saturated(sum_value):if sum_value > 255:sum_value = 255if sum_value < 0:sum_value = 0return sum_value
def sharpen(my_image):if is_grayscale(my_image):height, width = my_image.shapeelse:my_image = cv.cvtColor(my_image, cv.CV_8U)height, width, n_channels = my_image.shaperesult = np.zeros(my_image.shape, my_image.dtype) for j in range(1, height - 1):for i in range(1, width - 1):if is_grayscale(my_image):sum_value = 5 * my_image[j, i] - my_image[j + 1, i] - my_image[j - 1, i] \- my_image[j, i + 1] - my_image[j, i - 1]result[j, i] = saturated(sum_value)else:for k in range(0, n_channels):sum_value = 5 * my_image[j, i, k] - my_image[j + 1, i, k] \- my_image[j - 1, i, k] - my_image[j, i + 1, k]\- my_image[j, i - 1, k]result[j, i, k] = saturated(sum_value) return result
def main(argv):filename = 'lena.jpg'img_codec = cv.IMREAD_COLORif argv:filename = sys.argv[1]if len(argv) >= 2 and sys.argv[2] == "G":img_codec = cv.IMREAD_GRAYSCALEsrc = cv.imread(cv.samples.findFile(filename), img_codec)if src is None:print("Can't open image [" + filename + "]")print("Usage:")print("mat_mask_operations.py [image_path -- default lena.jpg] [G -- grayscale]")return -1cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)cv.namedWindow("Output", cv.WINDOW_AUTOSIZE)cv.imshow("Input", src)t = round(time.time())dst0 = sharpen(src)t = (time.time() - t)print("Hand written function time passed in seconds: %s" % t)cv.imshow("Output", dst0)cv.waitKey()t = time.time() kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]], np.float32) # kernel should be floating point type dst1 = cv.filter2D(src, -1, kernel)# ddepth = -1, means destination image has depth same as input image t = (time.time() - t)print("Built-in filter2D time passed in seconds: %s" % t)cv.imshow("Output", dst1)cv.waitKey(0)cv.destroyAllWindows()return 0
if __name__ == "__main__":main(sys.argv[1:])

基本方法

现在让我们看看如何通过使用基本的像素访问方法或使用 filter2D() 函数来实现这一点。

下面是一个函数,可以执行此操作:

C++代码;

def is_grayscale(my_image):return len(my_image.shape) < 3
def saturated(sum_value):if sum_value > 255:sum_value = 255if sum_value < 0:sum_value = 0return sum_value
def sharpen(my_image):if is_grayscale(my_image):height, width = my_image.shapeelse:my_image = cv.cvtColor(my_image, cv.CV_8U)height, width, n_channels = my_image.shaperesult = np.zeros(my_image.shape, my_image.dtype) for j in range(1, height - 1):for i in range(1, width - 1):if is_grayscale(my_image):sum_value = 5 * my_image[j, i] - my_image[j + 1, i] - my_image[j - 1, i] \- my_image[j, i + 1] - my_image[j, i - 1]result[j, i] = saturated(sum_value)else:for k in range(0, n_channels):sum_value = 5 * my_image[j, i, k] - my_image[j + 1, i, k] \- my_image[j - 1, i, k] - my_image[j, i + 1, k]\- my_image[j, i - 1, k]result[j, i, k] = saturated(sum_value) return result

Java代码:

 public static double saturate(double x) {return x > 255.0 ? 255.0 : (x < 0.0 ? 0.0 : x);}public Mat sharpen(Mat myImage, Mat Result) {myImage.convertTo(myImage, CvType.CV_8U);int nChannels = myImage.channels();Result.create(myImage.size(), myImage.type());for (int j = 1; j < myImage.rows() - 1; ++j) {for (int i = 1; i < myImage.cols() - 1; ++i) {double sum[] = new double[nChannels];for (int k = 0; k < nChannels; ++k) {double top = -myImage.get(j - 1, i)[k];double bottom = -myImage.get(j + 1, i)[k];double center = (5 * myImage.get(j, i)[k]);double left = -myImage.get(j, i - 1)[k];double right = -myImage.get(j, i + 1)[k];sum[k] = saturate(top + bottom + center + left + right);}Result.put(j, i, sum);}}Result.row(0).setTo(new Scalar(0));Result.row(Result.rows() - 1).setTo(new Scalar(0));Result.col(0).setTo(new Scalar(0));Result.col(Result.cols() - 1).setTo(new Scalar(0));return Result;}

Python代码

def is_grayscale(my_image):return len(my_image.shape) < 3
def saturated(sum_value):if sum_value > 255:sum_value = 255if sum_value < 0:sum_value = 0return sum_value
def sharpen(my_image):if is_grayscale(my_image):height, width = my_image.shapeelse:my_image = cv.cvtColor(my_image, cv.CV_8U)height, width, n_channels = my_image.shaperesult = np.zeros(my_image.shape, my_image.dtype) for j in range(1, height - 1):for i in range(1, width - 1):if is_grayscale(my_image):sum_value = 5 * my_image[j, i] - my_image[j + 1, i] - my_image[j - 1, i] \- my_image[j, i + 1] - my_image[j, i - 1]result[j, i] = saturated(sum_value)else:for k in range(0, n_channels):sum_value = 5 * my_image[j, i, k] - my_image[j + 1, i, k] \- my_image[j - 1, i, k] - my_image[j, i + 1, k]\- my_image[j, i - 1, k]result[j, i, k] = saturated(sum_value) return result

首先,我们确保输入图像数据采用无符号字符格式。为此,我们使用cv::CV_Assert 函数,当其中的表达式为 false 时,该函数会抛出错误。

 CV_Assert(myImage.depth() == CV_8U); // 只接受 uchar 图片

我们创建一个与输入具有相同大小和类型的输出图像。正如您在存储部分中看到的那样,根据通道的数量,我们可能有一个或多个子列。

我们将通过指针遍历它们,因此元素的总数取决于这个数字。

const int nChannels = myImage.channels();
Result.create(myImage.size(),myImage.type());

我们将使用普通的 C [] 运算符来访问像素。因为我们需要同时访问多行,所以我们将获取每行的指针(上一行、当前行和下一行)。我们需要另一个指向要保存计算位置的指针。然后,只需使用 [] 运算符访问正确的项目即可。为了将输出指针向前移动,我们只需在每次操作后增加此值(一个字节):

 for(int j = 1 ; j < myImage.rows-1; ++j){const uchar* previous = myImage.ptr<uchar>(j - 1);const uchar* current = myImage.ptr<uchar>(j );const uchar* next = myImage.ptr<uchar>(j + 1);uchar* output = Result.ptr<uchar>(j);for(int i= nChannels;i < nChannels*(myImage.cols-1); ++i){output[i] = saturate_cast<uchar>(5*current[i]-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);}}

在图像的边框上,上面的符号会导致不存在的像素位置(如负一 - 负一)。在这些方面,我们的公式是未定义的。一个简单的解决方案是不在这些点上应用内核,例如,将边框上的像素设置为零:

 Result.row(0).setTo(Scalar(0));Result.row(Result.rows-1).setTo(Scalar(0));Result.col(0).setTo(Scalar(0));Result.col(Result.cols-1).setTo(Scalar(0));

filter2D 函数
 

应用这种过滤器在图像处理中非常普遍,以至于在 OpenCV 中有一个函数可以负责应用掩码(在某些地方也称为内核)。为此,您首先需要定义一个包含掩码的对象:

C++代码:

 Mat kernel = (Mat_<char>(3,3) << 0, -1, 0,-1, 5, -1,0, -1, 0);

 然后调用 filter2D() 函数,指定要使用的输入、输出图像和内核:

 filter2D( src, dst1, src.depth(), kernel );

 Java代码:

 Mat kern = new Mat(3, 3, CvType.CV_8S);int row = 0, col = 0;kern.put(row, col, 0, -1, 0, -1, 5, -1, 0, -1, 0);

 然后调用 filter2D() 函数,指定要使用的输入、输出图像和内核:

 Imgproc.filter2D(src, dst1, src.depth(), kern);

Python代码:

 kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]], np.float32) # kernel should be floating point type

 然后调用 filter2D() 函数,指定要使用的输入、输出图像和内核: 

 dst1 = cv.filter2D(src, -1, kernel)# ddepth = -1, means destination image has depth same as input image

该函数甚至还有第五个可选参数来指定内核的中心,第六个参数用于在将过滤后的像素存储在 K 中之前向它们添加可选值,第七个参数用于确定在未定义操作的区域(边界)中执行的操作。

此函数更短,更不冗长,并且由于进行了一些优化,因此通常比手动编码方法更快。例如,在我的测试中,第二个测试只用了 13 毫秒,而第一个测试大约需要 31 毫秒。相当有区别。

例如:

resultMatMaskFilter2D.png

在我们的 YouTube 频道上查看运行该程序的实例。

参考文章:

1、《Mask operations on matrices》-----Bernát Gábor

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/778944.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海外媒体发稿:3种媒体宣发套餐内容推广方法

现如今&#xff0c;伴随着信息技术的不断进步和推广&#xff0c;新闻媒体宣发变成企业品牌推广的重要手段之一。为了方便让新闻信息新闻资讯传递给目标群体&#xff0c;公司一般会选择不同的套餐内容和推广方法。下面我们就详细介绍3种新闻资讯新闻媒体宣发套餐内容推广方法。 …

kubernetes(K8S)学习(九):K8S之日志监控

K8S之日志监控 一、Log and Monitor1.1 Log1.1.1 容器级别1.1.2 Pod级别1.1.3 组件服务级别1.1.4 LogPilot ES Kibana 1.2 Monitor1.2.1 Prometheus简介1.2.2 Prometheus架构1.2.3 Prometheus知识普及1.2.4 数据采集1.2.5 Prometheus Grafana 二、Trouble Shooting&#xff…

项目Weblogic切换Tomcat-包含数据源配置

目录 准备工作 修改Tomcat配置 Tomcat数据源加密 解密 加密 部署 问题解决 1.执行启停脚本时候&#xff0c;爆出&#xff1a;Cannot find ./catalina.sh The file is absent or does not have... 2.org.apache.catalina.core.StandardService.initInternal Failed to …

UE中:200W个对象单场景实现(待更新)

实现背景&#xff1a;需要显示城市级的行人以及地理市级范围内的路灯的状态&#xff0c;行人需要有状态以及位置的更新&#xff0c;路灯只需要状态的更新&#xff0c;二者都不需要物理 方案1概述&#xff1a;Niagara粒子系统实现 实际效果展示 UE5 集群模拟&#xff08;20W&a…

Oracle 控制文件详解

1、控制文件存储的数据信息 1&#xff09;数据库名称和数据库唯一标识符&#xff08;DBID) 2&#xff09;创建数据库的时间戳 3&#xff09;有关数据文件、联机重做日志文件、归档重做日志文件的信息 4&#xff09;表空间信息 5&#xff09;检查点信息 6&#xff09;日志序列号…

硬件10、从网站获取封装

百度搜索IC封装网或者网址https://www.iclib.com/ 搜索想要的器件&#xff0c;直接下载他的原理图库和封装库

1.Mysql基础入门—MySQL-mysql 8.0.11安装教程

1.Mysql基础入门—MySQL-mysql 8.0.11安装教程 摘要个人简介下载Mysql安装Mysql配置环境变量 摘要 MySQL 8.0.11的安装过程涉及几个关键步骤&#xff0c;首先访问MySQL官方网站下载页面&#xff0c;选择操作系统相对应的MySQL版本进行下载。对于Windows用户&#xff0c;启动下…

SpringCloudConfig 使用git搭建配置中心

一 SpringCloudConfig 配置搭建步骤 1.引入 依赖pom文件 引入 spring-cloud-config-server 是因为已经配置了注册中心 <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</…

浅谈 kafka

引言 同事在公司内部分享了关于 kafka 技术一些相关的内容&#xff0c;所以有了这篇文章&#xff1b;部分图片选自网络摘抄&#xff1b; 1 Kafka概述 1.1 定义 Kafka传统定义&#xff1a;kafka是一个分布式的基于发布/订阅模式的消息队列。 Kafka最新定义&#xff1a;kafka…

iOS UIFont-实现三方字体的下载和使用

UIFont 系列传送门 第一弹加载本地字体:iOS UIFont-新增第三方字体 第二弹加载线上字体:iOS UIFont-实现三方字体的下载和使用 前言 在上一章我们完成啦如何加载使用本地的字体。如果我们有很多的字体可供用户选择,我们当然可以全部使用本地字体加载方式,可是这样就增加了…

在项目中缓存如何优化?SpringCache接口返回值的缓存【CachePut、CacheEvict、Cacheable】

SpringCache 介绍&#xff08;不同的缓存技术有不同的CacheManager&#xff09;注解入门程序环境准备数据库准备环境准备注入CacheManager引导类上加EnableCaching CachePut注解(缓存方法返回值)1). 在save方法上加注解CachePut2). 测试 CacheEvict注解&#xff08;清理指定缓存…

开源AI引擎|信息抽取与文本分类项目案例:提升12345政务投诉处理效率

一、实际案例介绍 采集员案件上报流程是城市管理和问题解决的关键环节&#xff0c;涉及对案件类别的选择、案件来源的记录、详细案件描述的填写以及现场图片的上传。这一流程要求采集员准确、详细地提供案件信息&#xff0c;以便系统能够自动解析关键数据并填写相关内容&#…

ip地址改变导致nacos无法登录的解决方法

ip地址改变导致nacos无法登录的解决方法 在做黑马的springcloud课程里的黑马商城微服务项目时&#xff0c;发现使用nacos的默认账号密码&#xff08;nacos&#xff0c;nacos&#xff09;无法登录&#xff0c;项目里也没报错信息&#xff0c;虽然猜测和ip地址改变有关&#xff0…

算法---动态规划练习-6(地下城游戏)

地下城游戏 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 首先&#xff0c;定义一个二维数组 dp&#xff0c;其中 dp[i][j] 表示从位置 (i, j) 开始到达终点时的最低健康点数。 初始化数组 dp 的边界条件&#xff1a; 对…

机器学习作业二之KNN算法

KNN&#xff08;K- Nearest Neighbor&#xff09;法即K最邻近法&#xff0c;最初由 Cover和Hart于1968年提出&#xff0c;是一个理论上比较成熟的方法&#xff0c;也是最简单的机器学习算法之一。该方法的思路非常简单直观&#xff1a;如果一个样本在特征空间中的K个最相似&…

数字化运维实战手册:构建高效运维体系的方法与实践

一本书掌握数字化运维方法&#xff0c;构建数字化运维体系 数字化转型已经成为大势所趋&#xff0c;各行各业正朝着数字化方向转型&#xff0c;利用数字化转型方法论和前沿科学技术实现降本、提质、增效&#xff0c;从而提升竞争力。 数字化转型是一项长期工作&#xff0c;包含…

Mybatis中QueryWrapper的复杂查询SQL

最近在使用QueryWrapper编写查询语句时发现复杂的SQL不会写。在网上找了半天&#xff0c;终于得到了点启示。在此做个记录以备忘。 我要实现的SQL是这样的&#xff1a; -- 实现这个复杂查询 -- 查询设备表 select * from oa_device where ((dev_code BSD1003 and dev_status…

[flume$1]记录一个启动flume配置的错误

先总结&#xff1a;Flume配置文件后面&#xff0c;不能跟注释 报错代码&#xff1a; [ERROR - org.apache.flume.SinkRunner$PollingRunner.run(SinkRunner.java:158)] Unable to deliver event. Exception follows. org.apache.flume.EventDeliveryException: Failed to open…

Termius for Mac/Win:多协议远程管理利器,你的工作效率提升神器

在数字化飞速发展的今天&#xff0c;远程管理已成为企业运营和个人工作不可或缺的一部分。而Termius&#xff0c;作为一款多协议远程管理软件&#xff0c;正以其卓越的性能和便捷的操作&#xff0c;成为广大用户的心头好。 Termius支持多种协议&#xff0c;无论是SSH、RDP还是…

查询优化-提升子查询-UNION类型

瀚高数据库 目录 文档用途 详细信息 文档用途 剖析UNION类型子查询提升的条件和过程 详细信息 注&#xff1a;图片较大&#xff0c;可在浏览器新标签页打开。 SQL: SELECT * FROM score sc, LATERAL(SELECT * FROM student WHERE sno 1 UNION ALL SELECT * FROM student…