Refs: https://docs.opencv.org/4.3.0/d7/d37/tutorial_mat_mask_operations.html

目录

思想

The Basic Method

C++

修改像素

最后填充图像边缘

Python

Java

The filter2D function

C++

Python

Java

完整示例

C++

Python

Java


Mask operations on matrices are quite simple. The idea is that we recalculate each pixel's value in an image according to a mask matrix (also known as kernel). This mask holds values that will adjust how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a mathematical point of view we make a weighted average, with our specified values.

思想

Let's consider the issue of an image contrast enhancement method. Basically we want to apply for every pixel of the image the following formula:

The Basic Method

C++

修改像素

void Sharpen(const Mat& myImage,Mat& Result)
{CV_Assert(myImage.depth() == CV_8U);  // accept only uchar imagesconst 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++ = 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));
}

*output++ = saturate_cast<uchar>(5*current[i]-current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);

以彩色三通道的图片为例 BGR

i为B值则 i+/- 3 才同一行上相邻的值, 上下两行的相邻值则是previous和next

数据在内存以BRG的顺序连续存储

*output++ 等同于 *(output++)

0, 1, 2,,,,m表示对各像素点上BRG值

最后填充图像边缘

On the borders of the image the upper notation results inexistent pixel locations (like minus one - minus one). In these points our formula is undefined. A simple solution is to not apply the kernel in these points and, for example, set the pixels on the borders to zeros:

    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));

Python

At first we make sure that the input images data in unsigned 8 bit format.

my_image = cv.cvtColor(my_image, cv.CV_8U)

We create an output image with the same size and the same type as our input. As you can see in the storing section, depending on the number of channels we may have one or more subcolumns.

height, width, n_channels = my_image.shape
result = np.zeros(my_image.shape, my_image.dtype)

We need to access multiple rows and columns which can be done by adding or subtracting 1 to the current center (i,j). Then we apply the sum and put the new value in the Result matrix.

    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)

这个比c++的要好理解的多

为什么没有像c++一样填充边缘

Java

We need to access multiple rows and columns which can be done by adding or subtracting 1 to the current center (i,j). Then we apply the sum and put the new value in the Result matrix.

        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);}}

On the borders of the image the upper notation results in inexistent pixel locations (like (-1,-1)). In these points our formula is undefined. A simple solution is to not apply the kernel in these points and, for example, set the pixels on the borders to zeros:

        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));

与C++相类似要填充边缘

The filter2D function

C++

Applying such filters are so common in image processing that in OpenCV there is a function that will take care of applying the mask (also called a kernel in some places). For this you first need to define an object that holds the mask:

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

The function even has a fifth optional argument to specify the center of the kernel, a sixth for adding an optional value to the filtered pixels before storing them in K and a seventh one for determining what to do in the regions where the operation is undefined (borders).

This function is shorter, less verbose and, because there are some optimizations, it is usually faster than the hand-coded method.

Python

to define an object that holds the mask:

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

Then call the filter2D() function specifying the input, the output image and the kernel to use:

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

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);

其它与C++相类似

完整示例

C++

#include <iostream>
#include <opencv.hpp>
#include <ctime>using namespace cv;
using namespace std;void Sharpen(const Mat& myImage, Mat& Result);int main(int argc, char* argv[])
{Mat image_grass = imread("Grass.jpg", IMREAD_COLOR);//Mat image_grass = imread("Grass.jpg", IMREAD_GRAYSCALE);if (!image_grass.data){printf("No data\n");return -1;}pyrDown(image_grass, image_grass, Size(image_grass.cols / 2, image_grass.rows / 2));Mat src(image_grass);Mat dst0, dst1;namedWindow("Input", WINDOW_AUTOSIZE);namedWindow("Output", WINDOW_AUTOSIZE);namedWindow("MyOutput", 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("MyOutput", dst1);waitKey();return EXIT_SUCCESS;
}void Sharpen(const Mat& myImage, Mat& Result)
{CV_Assert(myImage.depth() == CV_8U);  // accept only uchar imagesconst 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++ = 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));
}

Python

from __future__ import print_function
import sys
import timeimport numpy as np
import cv2 as cvdef is_grayscale(my_image):return len(my_image.shape) < 3def saturated(sum_value):if sum_value > 255:sum_value = 255if sum_value < 0:sum_value = 0return sum_valuedef sharpen1(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 resultdef 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 i in range(1, height - 1):for j in range(1, width - 1):if is_grayscale(my_image):sum_value = 5 * my_image[i, j] - my_image [i-1, j] \-my_image[i+1, j] - my_image[i, j +1] -my_image[i, j-1]result[i, j] = saturated(sum_value)else:for k in range(0, n_channels):sum_value = 5* my_image[i, j, k] - my_image [i-1, j, k] \-my_image[i+1, j, k] - my_image[i, j +1, k] -my_image[i, j-1, k]result[i, j, k] = saturated(sum_value)return resultdef main():image = cv.imread("Grass.jpg", cv.IMREAD_COLOR)if image is None:print("No data")print("水光潋滟晴方好,山色空蒙雨亦奇。")else:print("欲把西湖比西子,淡妆浓抹总相宜。")src = cv.pyrDown(image)cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)cv.namedWindow("Output", cv.WINDOW_AUTOSIZE)cv.namedWindow("myOutput", cv.WINDOW_AUTOSIZE)cv.imshow("Input", src)# cv.waitKey()t = round(time.time())dst0 = sharpen(src)t = time.time() - tprint("Hand written function time passed in seconds: %s" % t)cv.imshow("Output", dst0)t = time.time()kernel = np.array([[0, -1, 0],[-1, 5, -1],[0, -1, 0]], np.float )# kernel should be floating point typedst1 = cv.filter2D(src, -1, kernel)# depth = -1, means destination image has depth same as input imaget = time.time() - tprint("Built-in filter2D time passed in seconds:     %s" % t)cv.imshow("myOutput", dst1)cv.waitKey()cv.destroyAllWindows()def readImageTest():image = cv.imread("Grass.jpg", cv.IMREAD_COLOR)if image is not None:pyrImage = cv.pyrDown(image)cv.namedWindow("Input", cv.WINDOW_AUTOSIZE)cv.imshow("Input", pyrImage)cv.waitKey()else:print("No data")if __name__ == "__main__":# readImageTest()main()

Java

package com.company;import java.util.Scanner;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;public class Main {static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }public static void main(String[] args) {System.out.println("Welcome to OpenCV " + Core.VERSION);
//            String filename = "././wolf.jpg";String filename = "Grass.jpg";int img_codec = Imgcodecs.IMREAD_COLOR;Mat src = Imgcodecs.imread(filename, img_codec);Imgproc.pyrDown(src, src);HighGui.namedWindow("Input", 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 static 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;}
}

Improving Opencv 3 : Mask operations on matrices相关推荐

  1. OpenCV:mask的作用,如何制作掩模mask

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.mask是什么? 二.OpenCV生成mask的几种方法 矩形 圆形 总结 前言 OpenCV中的很多函数用到ma ...

  2. opencv中mask参数

    其实opencv 里面很多函数都是会带有一个mask 参数的,很多同学都不知道它到底有什么用,好像在实际运用中忽略它也没有什么问题(这不废话嘛,opencv设计师设计它的时候默认就是可以忽略的). 我 ...

  3. 利用opencv添加mask

    第一种做法: import os import sys import random import math import numpy as np import skimage.io import ma ...

  4. opencv通过mask取目标纯色背景图

    import cv2 import numpy as np'''通过掩码图得到纯色背景的目标 '''rgb = cv2.imread(r'rgb.jpg') mask = cv2.imread(r'm ...

  5. 使用Python,OpenCV制作图像Mask——截取ROIs及构建透明的叠加层

    使用Python,OpenCV制作图像Mask--截取ROIs及构建透明的叠加层 1. 效果图 2. 源码 参考 这篇博客将介绍如何使用OpenCV制作Mask图像掩码.使用位运算和图像掩码允许我们只 ...

  6. 在OpenCV中使用Mask R-CNN

    本文翻译自:https://www.pyimagesearch.com/2018/11/19/mask-r-cnn-with-opencv/ 在本教程中,您将学习如何在OpenCV中使用Mask R- ...

  7. 一文详解OpenCV中的CUDA模块

    如果您使用OpenCV已有一段时间,那么您应该已经注意到,在大多数情况下,OpenCV都使用CPU,这并不总能保证您所需的性能.为了解决这个问题,OpenCV在2010年增加了一个新模块,该模块使用C ...

  8. 【opencv 450 core】使用统一向量指令(Universal Intrinsics)对代码进行矢量化

    Vectorizing your code using Universal Intrinsics 使用 Universal Intrinsics 对代码进行矢量化 Goal 本教程的目标是提供使用通用 ...

  9. 计算机视觉课程第十三讲-OpenCV的整体框架介绍下半部分

    本次将主要讲解一下OpenCV的整体框架,这样会更有利于我们学习和运用该开源工具.OpenCV主要包含以下三部分: 1.opencv-主要分支,包含核心类型和函数,稳定的算法,构建的脚本和工具: 2. ...

  10. OpenCV持久化(二)

    如何利用OpenCV持久化自己的数据结构?我们来看看OpenCV中的一个例子. MyData.hpp定义自己的数据结构MyData如下: #ifndef MYDATA_HPP #define MYDA ...

最新文章

  1. [JS][C++]两题斐波那契数列:上台阶、triangle
  2. tensorflow-tensorboard 0.4.0rc3 has requirement bleach==1.5.0, but you'll have bleach 2.0.0 which is
  3. 数字翻滚效果 HTML,js数字翻动效果 数字翻成中文怎么翻
  4. haproxy服务启动命令_HaProxy安装和常用命令
  5. java创建oracle用户_oracle添加用户并指定数据库
  6. [css] 请使用css3来模拟中/英文打字的效果
  7. datepicker动态初始化
  8. HTML section 标签
  9. 【2020模拟考试T3】【PAT乙】1028 人口普查 (20分) 字符串比较
  10. mysql管理工具_15款最佳的MySQL管理工具和应用程序
  11. Word中如何输入花体数学字符
  12. GAMES101现代计算机图形学入门-闫令琪-随堂笔记-Lecture 06 Rasterization 2 (Antialiasing and Z-Buffering)
  13. 数字电路中的时钟(2) PPM 计算
  14. ios苹果应用ipa一键签名工具_win和Mac电脑端自行签名ipa教程
  15. XP系统安装打印机提示未安装打印机驱动程序,操作无法完成.
  16. 算法工程师修仙之路:机器学习实战(四)
  17. [乡土民间故事_徐苟三传奇]第四四回_赵员外苕吃假香肠
  18. 企业邮箱发信数量是多少?
  19. adaboost.M1与adaboost.M2差别比较
  20. 榜样访谈——曾钰倬:从讲座中收获经验

热门文章

  1. 堆优化的Dijkstra
  2. Mismatch between array dtype (‘<U40‘) and format specifier (‘%.18e‘)
  3. 怎么让图片一直转圈_半夜跟着导航开进山路,货车绕了3小时仍原地转圈,小两口快急哭...
  4. mysql5.6.22.0安装_win2008 R2 WEB环境配置之MYSQL 5.6.22安装版安装配置方法
  5. java apns ssl错误_无法使用Javapns/Javaapns SSL握手失败发送推送通知
  6. linq分类汇总怎么写_包围结构的字怎么写才好看?掌握方法是关键,分类总结要领很实用...
  7. python爬虫简单步骤_python爬虫小demo,简单明了
  8. python制作二维码_教你使用Python制作酷炫二维码
  9. mongodb,Mysql,redis基础教程
  10. Html5 Canvas动画基础碰撞检测的实现