zoukankan      html  css  js  c++  java
  • 数字图象处理——仿射变换

    在《数字图象处理》中提供了基于
    这里写图片描写叙述
    图像仿射矩阵T。图像旋转、偏移变换等变换原理同样,依据这些在自己实现时。可分为三个步骤:

    1. 坐标转换
      这些变换是以图像的中心为坐标原点(O’(x’,y’)),而图片原本设定是以图像左上角为坐标原点(O(x,y))。

      所以要进行坐标的变换。
      这里写图片描写叙述
      用矩阵的方式表示:
      这里写图片描写叙述
      逆运算:
      这里写图片描写叙述

    2. 图像变换
      变换公式:
      这里写图片描写叙述
      逆运算:
      这里写图片描写叙述

    3. 坐标还原
      由于此时。坐标原点是在图像的中心。为方便操作须要将坐标原点又一次变换到图像左上角。
      从旋转后到旋转前的坐标变换为:
      这里写图片描写叙述
      (w’,h’是旋转后的图像的宽高);
      而逆运算为:
      这里写图片描写叙述 (1)

    以下是旋转的最邻近内插法和双线性内插法的实现:
    事实上在实现中。最重要的是求出变换后的图像宽高。再依据(1)式推出变换后的每个像素点相应的原图像坐标。依据(1)式计算原图像像素点坐标x,y时。结果中分别会有一个常量,用dx,dy表示。

    void nearestInterpolation(Mat &src, Mat &dst, float dx, float dy, double theta);
    int mainqqw()
    {
        cv::Mat src = imread("D:/xitong/picture/rain.jpg");
        namedWindow("orginal");
        imshow("orginal", src);
        int srcwidth = src.cols;
        int srcheigh = src.rows;
        /*旋转角度*/
        double theta = 30.0f*3.1415926 / 180.0f;
        /*
            转换坐标原点到图像中心
                    ∧y
                    |
                0   |   1
                    |
            --------o--------->x
                    |
                2   |   3
                    |
        */
        float srcX[4], srcY[4];
        srcX[0] = (float)(-((srcwidth - 1) / 2));
        srcX[1] = (float)((srcwidth - 1) / 2);
        srcX[2] = (float)(-(srcwidth - 1) / 2);
        srcX[3] = (float)((srcwidth - 1) / 2);
        srcY[0] = (float)((srcheigh - 1) / 2);
        srcY[1] = (float)((srcheigh - 1) / 2);
        srcY[2] = (float)(-(srcheigh - 1) / 2);
        srcY[3] = (float)(-(srcheigh - 1) / 2);
    
        /*
            旋转后的图像坐标,此时坐标原点依旧是旋转中心
        */
        float dstX[4], dstY[4];
        for (int i = 0; i < 4; i++)
        {
            dstX[i] = cos(theta)*srcX[i] + sin(theta)*srcY[i];
            dstY[i] = -sin(theta)*srcX[i] + cos(theta)*srcY[i];
        }
    
        /*
            ==>旋转后图像长宽
        */
        int dstwidth = (max(fabs(dstX[3] - dstX[0]), fabs(dstX[2] - dstX[1])) + 0.5);
        int dstheigh = (max(fabs(dstY[3] - dstY[0]), fabs(dstY[2] - dstY[1])) + 0.5);
    
        /*Mat dst = Mat(Size(src.rows * 2, src.cols * 2), src.type(), Scalar::all(0));
        nearestInterpolation(src, dst, 0.5);*/
        Mat dst;
        dst.create(dstheigh, dstwidth, src.type());
    
        //(1)式在运算后的常量。为运算方便提前的出结果
        float dx = -0.5*dstwidth*cos(theta) - 0.5*dstheigh*sin(theta) + 0.5*srcwidth;
        float dy = 0.5*dstwidth*sin(theta) - 0.5*dstheigh*cos(theta) + 0.5*srcheigh;
    
        nearestInterpolation(src, dst, dx, dy, theta);
        waitKey();
        return 0;
    }
    
    /*
        最邻近内插旋转
    */
    void nearestInterpolation(Mat &src, Mat &dst, float dx, float dy, double theta)
    {
        int x, y;
        for (int i = 0; i < dst.rows; i++)
        {
            for (int j = 0; j < dst.cols; j++)
            {
                /*
                    依据(1)式。推出相应原图像 像素坐标的运算结果
                */
                x = cvFloor(float(j)*cos(theta) + float(i)*sin(theta) + dx);
                y = cvFloor(float(-j)*sin(theta) + float(i)*cos(theta) + dy);
                if ((x < 0) || (x >= src.cols) || (y < 0) || (y >= src.rows))
                {
                    if (src.channels() == 3)
                        dst.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
                    if (src.channels() == 1)
                        dst.at<uchar>(i, j) = 0;
                }
                else
                {
                    if (src.channels() == 3)
                        dst.at<Vec3b>(i, j) = src.at<Vec3b>(y, x);
                    if (src.channels() == 1)
                        dst.at<uchar>(i, j) = src.at<uchar>(y, x);
                }
    
            }
        }
        namedWindow("最邻近内插旋转");
        imshow("最邻近内插旋转", dst);
    }
    /*
        双线性内插法旋转
    */
    void bilinearRotate(Mat &src, Mat &dst, float dx, float dy, double theta)
    {
        float fu, fv;
        int x, y;
        Vec3b point[4];
        uchar upoint[4];
        for (int j = 0; j < dst.rows; j++)
        {
            for (int i = 0; i < dst.cols; i++)
            {
                fu = float(j)*cos(theta) + float(i)*sin(theta) + dx;
                fv = float(-j)*sin(theta) + float(i)*cos(theta) + dy;
                x = cvFloor(fu);
                y = cvFloor(fv);
                fu -= x;
                fv -= y;
    
                if ((x < 0) || (x >= src.cols-1) || (y < 0) || (y >= src.rows-1))
                {
                    if (src.channels() == 3)
                        dst.at<Vec3b>(i, j) = Vec3b(0, 0, 0);
                    if (src.channels() == 1)
                        dst.at<uchar>(i, j) = 0;
                }
                else
                {
                    if (src.channels() == 3)
                    {
                        point[0] = src.at<Vec3b>(y, x);
                        point[1] = src.at<Vec3b>(y + 1, x);
                        point[2] = src.at<Vec3b>(y, x + 1);
                        point[3] = src.at<Vec3b>(y + 1, x + 1);
                        dst.at<Vec3b>(i, j) = (1 - fu)*(1 - fv)*point[0] + (1 - fu)*(fv)*point[1] + (1 - fv)*(fu)*point[2] + fu*fv*point[3];
                    }
    
                    if (src.channels() == 1)
                    {
                        upoint[0] = src.at<uchar>(y, x);
                        upoint[1] = src.at<uchar>(y + 1, x);
                        upoint[2] = src.at<uchar>(y, x + 1);
                        upoint[3] = src.at<uchar>(y + 1, x + 1);
                        dst.at<uchar>(i, j) = (1 - fu)*(1 - fv)*upoint[0] + (1 - fu)*(fv)*upoint[1] + (1 - fv)*(fu)*upoint[2] + fu*fv*upoint[3];
                    }
                }
            }
        }
        namedWindow("双线性内插法旋转");
        imshow("双线性内插法旋转", dst);
    }
  • 相关阅读:
    Effective Java 19 Use interfaces only to define types
    Effective Java 18 Prefer interfaces to abstract classes
    Effective Java 17 Design and document for inheritance or else prohibit it
    Effective Java 16 Favor composition over inheritance
    Effective Java 15 Minimize mutability
    Effective Java 14 In public classes, use accessor methods, not public fields
    Effective Java 13 Minimize the accessibility of classes and members
    Effective Java 12 Consider implementing Comparable
    sencha touch SortableList 的使用
    sencha touch dataview 中添加 button 等复杂布局并添加监听事件
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7210286.html
Copyright © 2011-2022 走看看