OpenCV(4)矩阵掩码操作/像素算数、逻辑操作 C++

18 篇文章 9 订阅

1. 矩阵上的掩码操作

1.1.(cv :: filter2D)矩阵上的掩码操作

1.2.(cv :: CV_Assert) 确保输入图像数据是unsigned char格式

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

 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) :表示目标像素点;i :表示像素点的横坐标;j :表示像素点的纵坐标
  • I(i-1,j) 、I(i+1,j) 、 I(i,j-1) 、 I(i,j+1):分别表示目标像素点周围的四个像素点
  • 上面公式的作用就是:让自己增加4倍,然后减去周围像素点的值,所得到的值便是自己新的值。如果目标像素颜色很鲜艳,它周围的像素点颜色不鲜艳,那么通过公式,目标点会变得更加鲜艳。相反,目标像素点会变得更加不鲜艳。
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/core/core.hpp>  
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argb[])
{
    Mat I = imread("../data/test2.jpg");
    if (I.empty()) {
        cout << "cannot read the image!" << endl;
        return 0;
    }
    Mat K;
    Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
    filter2D(I, K, I.depth(), kernel);
    imshow("original", I);
    imshow("sharpen", K);
    waitKey(0);
    return 0;
}

执行结果:
在这里插入图片描述

#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] : "../data/test2.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("Output1", WINDOW_AUTOSIZE);//创建窗口
    namedWindow("Output2", WINDOW_AUTOSIZE);//创建窗口
    imshow("Input", src);//显示图像
    //方法1: 自己写的函数
    double t = (double)getTickCount();//计时开始
    Sharpen(src, dst0);
    t = ((double)getTickCount() - t) / getTickFrequency();//计算时间
    cout << "Hand written function, 自己写的代码耗时: " << t << endl;//输出时间
    imshow("Output1", dst0);//显示图像
    //方法2: filter2D函数
    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 ,    filter2D耗时:     " << t << endl;//输出时间
    imshow("Output2", 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++ = 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));
}

执行结果:

Hand written function, 自己写的代码耗时: 0.0022542
Built-in filter2D ,    filter2D耗时:   0.0005542

2.图像像素的算术操作

2.1.加:add (src1, src2, addResult);

2.2.减:subtract (src1, src2, subResult);

2.3.乘:multiply (src1, src2, mulResult);

2.4.除:divide (src1, src2, divResult);

还可以使用以下方式进行:像素之间的 加、减、乘法
saturateResult.at(row, col)[0] = saturate_cast(b1 * b2);
saturateResult.at(row, col)[1] = saturate_cast(g1 * g2);
saturateResult.at(row, col)[2] = saturate_cast(r1 * r2);

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(int argv, char** argc)
{
    Mat src1 = imread("../data/test7.jpg");
    Mat src2 = imread("../data/test8.jpg");
    if (src1.empty() || src2.empty())
    {
        printf("Could not load image src1 or src2...\n");
        return -1;
    }
    Mat addResult = Mat::zeros(src1.size(), src1.type());
    add(src1, src2, addResult);
    imshow("addResult 加", addResult);
    Mat subResult = Mat::zeros(src1.size(), src1.type());
    subtract(src1, src2, subResult);
    imshow("subResult 减", subResult);
    Mat mulResult = Mat::zeros(src1.size(), src1.type());
    multiply(src1, src2, mulResult);
    imshow("mulResult 乘", mulResult);
    Mat divResult = Mat::zeros(src1.size(), src1.type());
    divide(src1, src2, divResult);
    imshow("divResult 除", divResult);
    int b1 = 0, g1 = 0, r1 = 0;
    int b2 = 0, g2 = 0, r2 = 0;
    //int b = 0, g = 0, r = 0;
    int height = src1.rows;
    int width = src1.cols;
    Mat saturateResult = Mat::zeros(src1.size(), src1.type());
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            b1 = src1.at<Vec3b>(row, col)[0];
            g1 = src1.at<Vec3b>(row, col)[1];
            r1 = src1.at<Vec3b>(row, col)[2];
            b2 = src2.at<Vec3b>(row, col)[0];
            g2 = src2.at<Vec3b>(row, col)[1];
            r2 = src2.at<Vec3b>(row, col)[2];
            saturateResult.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b1 + b2);
            saturateResult.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g1 + g2);
            saturateResult.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r1 + r2);
        }
    }
    imshow("saturateResult 相加", saturateResult);
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            b1 = src1.at<Vec3b>(row, col)[0];
            g1 = src1.at<Vec3b>(row, col)[1];
            r1 = src1.at<Vec3b>(row, col)[2];
            b2 = src2.at<Vec3b>(row, col)[0];
            g2 = src2.at<Vec3b>(row, col)[1];
            r2 = src2.at<Vec3b>(row, col)[2];
            saturateResult.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b1 * b2);
            saturateResult.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g1 * g2);
            saturateResult.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r1 * r2);
        }
    }
    imshow("saturateResult 相乘", saturateResult);
    waitKey(0);
    return 0;
}

执行结果:

加减乘除:
在这里插入图片描述

相加、相乘:
在这里插入图片描述

3.像素的逻辑操作

3.1.与:bitwise_and(src1, src2, dst1);

3.2.或:bitwise_or(src1, src2, dst2);

3.3.异或:bitwise_xor(src1, src2, dst3);

#include "opencv2\opencv.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
    //创建图片1
    Mat src1 = Mat::zeros(Size(400, 400), CV_8UC3);
    Rect rect(100, 100, 100, 100);
    src1(rect) = Scalar(0, 0, 255);//bgr
    imshow("input1", src1);
    printf("创建第一张图片...\n");
    //创建图片2
    Mat src2 = Mat::zeros(Size(400, 400), CV_8UC3);
    rect.x = 150;
    rect.y = 150;
    src2(rect) = Scalar(0, 0, 255);//bgr
    imshow("input2", src2);
    printf("创建第二张图片...\n");
    //取反操作
    Mat src = imread("../data/test2.jpg");
    imshow("input", src);
    Mat dst;
    bitwise_not(src, dst);
    //逻辑操作
    Mat dst1, dst2, dst3;
    bitwise_and(src1, src2, dst1);
    bitwise_or(src1, src2, dst2);
    bitwise_xor(src1, src2, dst3);
    //结果显示
    imshow("取反操作", dst);
    imshow("逻辑与", dst1);
    imshow("逻辑或", dst2);
    imshow("逻辑异或", dst3);
    waitKey(0);
    return 0;
}

执行结果:
在这里插入图片描述

逻辑与、逻辑或、逻辑异或:
在这里插入图片描述
取反操作:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

~晓广~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值