OpenCV 运动模糊的模拟 C++

运动模糊时,模糊后图片某点的值应该与原图沿运动角度方向前面的点有关,并且越近邻影响越大,即权值越大。所以除了确定卷积核之外,还确定了锚点(anchor)

OpenCV 运动模糊的模拟 C++_第1张图片

右下角60度移动,距离50

OpenCV 运动模糊的模拟 C++_第2张图片

代码实现:

 

#include "opencv2/opencv.hpp"

typedef cv::Mat Mat;
void genaratePsf(Mat &psf, cv::Point &anchor, double len,double angle);

int main(int argc, char * argv[])
{
    if( argc != 2){
        std::cerr << "Usage: " << argv[0] << " " << std::endl;
        return -1;
    }

    Mat srcImage = cv::imread(argv[1], cv::IMREAD_COLOR);
    if( srcImage.empty() )
        return -1;
    imshow( "src_img", srcImage );
    double len = 50;
    double angle = -60;
    Mat ker, dst;
    cv::Point anchor;
    genaratePsf(ker, anchor, len, angle);

    /// 使用滤波器
    filter2D(srcImage, dst, -1 , ker, anchor );

//    cv::normalize(dst_plane[0], dst_plane[0], 1, 0, CV_MINMAX);
    imshow( "dest", dst );
    cv::waitKey(0);

    return 1;
}


void genaratePsf(Mat &psf, cv::Point &anchor, double len,double angle)
{
    //生成卷积核和锚点
    double half=len/2;
    double alpha = (angle-floor(angle/ 180) *180) /180* CV_PI;
    double cosalpha = cos(alpha);
    double sinalpha = sin(alpha);
    int xsign;
    if (cosalpha < 0){
        xsign = -1;
    } else {
        if (angle == 90) {
            xsign = 0;
        } else {
            xsign = 1;
        }
    }
    int psfwdt = 1;
    //模糊核大小
    int sx = (int)fabs(half*cosalpha + psfwdt*xsign - len*FLT_EPSILON );
    int sy = (int)fabs(half*sinalpha + psfwdt - len*FLT_EPSILON);
    cv::Mat_ psf1(sy, sx, CV_64F);

    //psf1是左上角的权值较大,越往右下角权值越小的核。
    //这时运动像是从右下角到左上角移动
    for (int i = 0; i < sy; i++){
        double* pvalue = psf1.ptr(i);
        for (int j = 0; j < sx; j++){
            pvalue[j] = i*fabs(cosalpha) - j*sinalpha;

            double rad = sqrt(i*i + j*j);
            if (rad >= half && fabs(pvalue[j]) <= psfwdt){
                double temp = half - fabs((j + pvalue[j] * sinalpha) / cosalpha);
                pvalue[j] = sqrt(pvalue[j] * pvalue[j] + temp*temp);
            }
            pvalue[j] = psfwdt + FLT_EPSILON - fabs(pvalue[j]);
            if (pvalue[j] < 0){
                pvalue[j] = 0;
            }
        }
    }
//    运动方向是往左上运动,锚点在(0,0)
    anchor.x = 0;
    anchor.y = 0;
//    运动方向是往右上角移动,锚点一个在右上角
//    同时,左右翻转核函数,使得越靠近锚点,权值越大
    if (angle<90 && angle>0){
        flip(psf1, psf1, 1);
        anchor.x =psf1.cols-1;
        anchor.y = 0;
    }else if( angle>-90 && angle<0){    //同理:往右下角移动
            flip(psf1, psf1, -1);
            anchor.x =psf1.cols-1;
            anchor.y = psf1.rows-1;
    }else if( angle<-90){   //同理:往左下角移动
            flip(psf1, psf1, 0);
            anchor.x = 0;
            anchor.y = psf1.rows-1;
    }
    /*保持图像总能量不变,归一化矩阵*/
    double sum = 0;
    for (int i = 0; i < sy; i++) {
        for (int j = 0; j < sx; j++){
            sum+= psf1[i][j];
        }
    }
    psf = psf1 / sum;
}
 

参考:

https://www.cnblogs.com/wyh1993/p/7118559.html

https://blog.csdn.net/lei_yin/article/details/27318955

你可能感兴趣的:(OpenCV,C++,数字图像处理,OpenCV,C++数字图像处理,冈萨雷斯第三版)