openCV学习记录:滤镜:木刻&怀旧

木刻滤镜

木刻滤镜其实就是图像的二值化处理。图像的二值化处理就是将每个像素点的RGB分量值设成0或255。进行图像二值化之前,先将图像做灰度化处理,灰度化就是把每个像素点的RGB分量值设成一样大。图像的灰度化处理有三种方法:最大值法,平均法或权值法。

最大值法:顾名思义就是取RGB三个分量的最大值作为灰度值,即:gray=max(R,G,B),这种方法转化的灰度图亮度很高。

平均值法:就是取RGB三个分量的平均值作为灰度值,即:gray=(R+G+B)/ 3。这种方法产生的灰度图比较柔和。

权值法:对RGB三个分量按不同的比率取值的和作为灰度值。由于人眼对绿色最为敏感,红色次之,对蓝色的敏感性最低,因此将得到较易识别的灰度图像。一般得到的灰度图像效果最好。公式如下:
Gray = 0.30R + 0.59G + 0.11B 。

二值化就是在灰度图像的基础上,所有灰度值大于或等于阀值的像素被判定为属于特定物体,其灰度值为255表示,否则这些像素点被排除在物体区域以外,灰度值为0,表示背景或者例外的物体区域。公式如下:
gray = gray > 阀值 ? 255 : 0。为了实现木刻滤镜,阀值设成127.

openCV有专门的图像灰度化处理函数:cvtColor()

void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )

参数说明:

  • src:输入图像
  • dst:输出图像
  • code:颜色空间转换码,这个值决定转换模式,要想将彩色图像转成灰度图像,这个值设成:CV_BGR2GRAY
  • dstCn:一般为0

这个函数可以将图像在RGB,HSV ,HLS,Gray等多种模式间互相转换,第三个参数决定以哪种模式转换。
用该函数对彩色图像灰度化以后,图像会由三通道变成一通道。
完整版代码如下:

void muKeFilter(Mat &srcImage){
    Mat dstImage = srcImage;
    cvtColor(dstImage,dstImage,CV_BGR2GRAY);

    int rowNum = dstImage.rows;//要处理的行数
    int colNum = dstImage.cols ;//要处理的列数

    for(int j = 0;j<rowNum;j++){
        uchar * row = dstImage.ptr<uchar>(j);
        for(int i = 0;i<colNum ;i++){
            row[i] = row[i]  > 127 ? 255:0;
        }
    }
}

如果不用cvtColor()函数对彩色图像做灰度化预处理,直接用自己的代码对图像灰度化处理,像下面的代码:

int rowNum = srcImage.rows;//要处理的行数
int colNum = srcImage.cols ;//要处理的列数

for(int j = 0;j<rowNum;j++){
    uchar * row = srcImage.ptr<uchar>(j);
    for(int i = 0;i<colNum ;i++){
        int gray = (row[i*3] + row[i*3+1] + row[i*3+2])/3  > 127 ? 255:0;//二值化
        row[i*3] = gray;
        row[i*3+1] = gray;
        row[i*3+2] = gray;
    }
}

这时候,图像还是三通道的。

openCV里有一个专门的二值化函数

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)

参数说明:

  • src: 输入图像,必须是单通道的
  • dst: 输出图像
  • thresh: 阀值
  • maxval: 最大值
  • type: 设定值的方法,有五种,如下图

    type

所以这个滤镜用最简单的方法写的话,代码很少,如下:

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

using namespace cv;
using namespace std;

void muKeFilter(Mat &srcImage);

int main(){
    Mat srcImage = imread("lena.jpg");

    if(!srcImage.data || srcImage.empty()){
        cout<<"读入图片错误!"<<endl;
        return -1;
    }

    imshow("原图",srcImage);

    muKeFilter(srcImage);

    waitKey(0);
    return 0;
}

 void muKeFilter(Mat &srcImage){
    Mat dstImage = srcImage;
    cvtColor(dstImage,dstImage,CV_BGR2GRAY);
    threshold(dstImage,dstImage,127,255,THRESH_BINARY);

    imshow("木刻滤镜",srcImage);
}

效果图:
这里写图片描述

下面这篇文章介绍了四种二值化方法:
图像二值化

怀旧滤镜

怀旧滤镜就是让照片有种发黄的效果。主要算法思想:

按以下公式计算新的RGB值:

int R = 0.393*r + 0.769*g + 0.189*b;
int G = 0.349*r + 0.686*g + 0.168*b;
int B = 0.272*r + 0.534*g + 0.131*b;

RGB的值要约束在0与255之间。

主要代码如下:

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

using namespace cv;
using namespace std;

void huaiJiuFilter(Mat &srcImage);

int main(){
    Mat srcImage = imread("lena.jpg");

    if(!srcImage.data || srcImage.empty()){
        cout<<"读入图片错误!"<<endl;
        return -1;
    }

    imshow("原图",srcImage);

    huaiJiuFilter(srcImage);

    waitKey(0);
    return 0;
}

  void huaiJiuFilter(Mat &srcImage){
    int rowNum = srcImage.rows;
    int colNum = srcImage.cols;

    for(int j = 0;j<rowNum;j++){
        uchar* data = srcImage.ptr<uchar>(j);
        for(int i = 0;i<colNum;i++){
            int b = data[i*3];
            int g = data[i*3+1];
            int r = data[i*3+2];

            int R = static_cast<int>(0.393*r + 0.769*g + 0.189*b);
            int G = static_cast<int>(0.349*r + 0.686*g + 0.168*b);
            int B = static_cast<int>(0.272*r + 0.534*g + 0.131*b);

            data[i*3+2] = max(0,min(R,255));
            data[i*3+1] = max(0,min(G,255));
            data[i*3] = max(0,min(B,255));  
        }
    }

    imshow("怀旧滤镜",srcImage);
}

效果图:

怀旧

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值