• OpenCV3入门(十四)图像特效—挤压、哈哈镜、扭曲


    一、图像挤压特效

    1、原理

    图像压效果本质的图像坐标的非线性变换,将图像向内挤压,挤压的过程产生压缩变形,从而形成的效果。

    挤压效果的实现是通过极坐标的形式,设图像中心为O(x,y),某点距离中心O的距离为半径R,非线性方式改变半径R但不改变点的方向,就构成了图像挤压。也可以自定义加压中心点,计算半径方式相同。

    图像像素变换倍率使用 y=sqrt(x)。

     图像上点P与图像中心O的距离为R,图像挤压就是P点坐标映射到OP直线上的点R2位置,其中| OR2 |=sqrt(OP)*ratio。

     

    2、实现

    void Pinch(Mat& img, Mat& dst, int degree)
    {
        if (degree < 1) degree = 1;
        if (degree > 32) degree = 32;
    
        if (dst.empty())
            dst.create(img.rows, img.cols, img.type());
        dst = cv::Scalar::all(0);
    
        int chns = img.channels();
        int height = img.rows;
        int width = img.cols;
    
        int midX = width / 2;
        int midY = height / 2;
        int i, j, k;
        int X, Y, offsetX, offsetY;
        double radian, radius;  //弧和半径
    
        for (i = 0; i < height; i++)
        {
            for (j = 0; j < width; j++)
            {
                offsetX = j - midX;
                offsetY = i - midY;
    
                radian = atan2((double)offsetY, (double)offsetX);
    
                // 半径
                radius = sqrtf((float)(offsetX*offsetX + offsetY * offsetY));
                radius = sqrtf(radius)*degree;
    
                X = (int)(radius*cos(radian)) + midX;
                Y = (int)(radius*sin(radian)) + midY;
    
                if (X < 0) X = 0;
                if (X >= width) X = width - 1;
                if (Y < 0) Y = 0;
                if (Y >= height) Y = height - 1;
    
                for (k = 0; k < chns; k++)
                {
                    dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(Y, X)[k];
                }
            }
        }
    }
    
    Mat src_img;
    Mat dst_img;
    int rato = 15;
    
    void call_back(int, void*)
    {
        Pinch(src_img, dst_img, rato);
        imshow("Pinch图", dst_img);
    }
    
    int main() {
    
        src_img = imread("D:\WORK\5.OpenCV\LeanOpenCV\pic_src\pic18.bmp");
        imshow("原图", src_img);
    
        Pinch(src_img, dst_img, rato);
        imshow("Pinch图", dst_img);
    
        namedWindow("Pinch图");
        createTrackbar("Pinch倍率", "Pinch图", &rato, 50, call_back);
        call_back(rato, 0);
    
        waitKey(0);
    }

    3、测试效果

    测试1

    测试2:不同倍率下棋盘格的挤压效果。

     二、哈哈镜特效

    1、原理

     图像坐标的非线性变换,实现k的根号与k的比值,sqrt(k)/k k1时总倍率为1,当k小于1时,总倍率为渐变倍率。

    2、实现

    void Pinch(Mat& img, Mat& dst, int x, int y, int degree)
    {
        if (dst.empty())
            dst.create(img.rows, img.cols, img.type());
    
        dst = cv::Scalar::all(0);
        cout << "x,y " << x << " " << y << endl;
    
        int chns = img.channels();
        int height = img.rows;
        int width = img.cols;
    
        midX = x;
        midY = y; 
        int R = 100;
    
        int i, j, k;
        int X, Y, offsetX, offsetY;
        double radian, radius;  //弧和半径
    
        for (i = 0; i < height; i++)
        {
            for (j = 0; j < width; j++)
            {
                offsetX = j - midX;
                offsetY = i - midY;
                 radian = atan2((double)offsetY, (double)offsetX);
    
                // 半径
                radius = sqrtf((float)(offsetX*offsetX + offsetY * offsetY));
                if (radius <= R &&  radius > 1) {
                    float k = sqrtf(radius/R) * radius / R * degree;
                    X = (int)( cos(radian) * k) + midX;
                    Y = (int)( sin(radian) * k) +  midY;
    
                    if (X < 0) X = 0;
                    if (X >= width) X = width - 1;
                    if (Y < 0) Y = 0;
                    if (Y >= height) Y = height - 1;
    
                    for (k = 0; k < chns; k++)
                    {
                        dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(Y, X)[k];
                    }
                }
                else 
                {
                    for (k = 0; k < chns; k++)
                    {
                        dst.at<Vec3b>(i, j)[k] = img.at<Vec3b>(i, j)[k];
                    }
                }
            }
        }
    
        cout << " midX, midY " << midX << " " << midY << endl;
    }

    3、测试效果

    测试1:哈哈镜效果

    测试2:大倍率呈现潜望镜效果。

    测试3:

    三、图像扭曲

    对图像的像素坐标进行正弦变换,映射到对应坐标就完成了图像扭曲。关键代码如下:

    for (int j = 0; j < width; j++)
    {
        double temp =  degree * sin(1.0 * j / width  *  pi * T ); // [-degree,degree]
        temp = degree + temp;  // [0, 2*degree]
        for (int i = int(temp + 0.5); i < height + temp - 2 * degree; i++)
        {
            X = (int)((i - temp) *  (height) / (height - degree));
            if (X >= img.rows)
                X = img.rows - 1;
            if (X < 0)
                X = 0;
    
            for (int c = 0; c < chns; c++)
            {
                dst.at<Vec3b>(i, j)[c] = img.at<Vec3b>(X, j)[c];
            }
        }
    }

    测试1:

    测试2:

    4、参考文献

    1、《学习OpenCV》,清华大学出版社,Gary Bradski, Adrian kaehler著

    2、仿射变换

    http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html

    3、PhotoShop算法实现高级篇--挤压特效(三十六)

    https://blog.csdn.net/kezunhai/article/details/41873775

     

    技术博客,转载请注明。

    https://www.cnblogs.com/pingwen/p/12503047.html

  • 相关阅读:
    许家骏
    平均得分 【杭州电-HDOJ-2023】 附加题+详细说明
    百度之星的第二个问题
    kendo ui 单击取消编辑数据grid减少的原因和治疗方法的数据
    2013年第36周准备考下半年的项目管理师
    2013年第36周三杂记
    2013第36周二小结
    2013第36周星期一
    2013年9月1日下午
    2013年8月最后一天晚上
  • 原文地址:https://www.cnblogs.com/pingwen/p/12503047.html
Copyright © 2020-2023  润新知