欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数字图像处理实验(六):图像旋转与缩放

程序员文章站 2024-01-28 09:03:34
...

一、实验内容与原理

1、空间变换:

空间变换对应矩阵的仿射变换。一个坐标通过函数变换的新的坐标位置:
数字图像处理实验(六):图像旋转与缩放
所以在程序中我们可以使用一个2*3的数组结构来存储变换矩阵:
数字图像处理实验(六):图像旋转与缩放
以最简单的平移变换为例,平移(b1,b2)坐标可以表示为:
数字图像处理实验(六):图像旋转与缩放
因此,平移变换的变换矩阵及逆矩阵记为:
数字图像处理实验(六):图像旋转与缩放

2、缩放变换:

将图像横坐标放大(或缩小)sx倍,纵坐标放大(或缩小)sy倍,变换矩阵及逆矩阵为:
数字图像处理实验(六):图像旋转与缩放

3、选择变换:

图像绕原点逆时针旋转a角,其变换矩阵及逆矩阵(顺时针,特别说明,图像的坐标轴与一般数学意义的坐标轴不同)为:
数字图像处理实验(六):图像旋转与缩放

二、实验代码

实验环境:
(1)OpenCV3.4.3
(2)Ubuntu16.04
(3)VS Code
(4)C++

// 图像的旋转 与 缩放
#include <stdio.h>  
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <string>

class Extra1{
public:
    Extra1(std::vector<std::string> path){
        for(int i = 0; i < path.size(); i++){
            // 读取彩色图片、灰度图片
            original_color_image.push_back(cv::imread(path[i]));
            original_gray_image.push_back(color2Gray(original_color_image[i]));
        }
    }
    // 0、彩色图像转灰度图像
    cv::Mat color2Gray(cv::Mat src_image){
        //创建与原图同类型和同大小的矩阵
	    cv::Mat gray_image(src_image.rows, src_image.cols, CV_8UC1);
        if(src_image.channels()!=1){
            for(int i = 0; i < src_image.rows; i++)
                for(int j = 0; j < src_image.cols; j++)
                    gray_image.at<uchar>(i, j) = (src_image.at<cv::Vec3b>(i, j)[0] + src_image.at<cv::Vec3b>(i, j)[1] + src_image.at<cv::Vec3b>(i, j)[2]) / 3;
        }
        else
            gray_image = src_image.clone();
        return gray_image;
    }
    // 2 旋转图像
    void RotateScalingImage(cv::Mat& src_image, int opt=1){
        int angle = 0, delta = 1;
        std::string s[] = {"仅仅旋转","旋转加缩放"}; 
        while(true){
            double factor;
            if(opt)
                factor = (cos(angle*CV_PI/180.) + 1.05)*2;
            else
                factor = 1;

            int w = src_image.cols, h = src_image.rows;
            cv::Mat rot_mat = cv::Mat(2, 2, CV_32F);
            //             
            // [ m0 m1 m2 ]  ===> [ A11 A12   b1 ] ===> [cos(a)  sin(a)  b1]            
            // [ m3 m4 m5 ]  ===> [ A21 A22   b2 ] ===> [-sin(a) cos(a)  b2]
            //  
            rot_mat.at<float>(0, 0) = (float)(factor*cos(-angle*2*CV_PI/180.));     
            rot_mat.at<float>(0, 1) = (float)(factor*sin(-angle*2*CV_PI/180.));     
            rot_mat.at<float>(1, 0) = -rot_mat.at<float>(0, 1);     
            rot_mat.at<float>(1, 1) = rot_mat.at<float>(0, 0);                    
            // dst(x,y) = A * src(x,y) + b
            cv::Mat rotate_image = cv::Mat::zeros(src_image.rows, src_image.cols, src_image.type());
            realizeRotateScaling(src_image, rot_mat, rotate_image);
            //cv::Mat middle_filter_image = cv::Mat::zeros(rotate_image.rows, rotate_image.cols, rotate_image.type());
            grayFiltering(rotate_image);
            
            cv::imshow(s[opt], rotate_image);
            if(cv::waitKey(5) == 27)
                break;
            angle =(int)(angle + delta) % 360;   
        }
        return; 
    }
    // 2.1 实现旋转 与 缩放 操作
    void realizeRotateScaling(cv::Mat& src, cv::Mat& rotmat, cv::Mat& dst){
        int i, j, i1, j1;
        int centeri = src.rows/2, centerj = src.cols/2;
        for(i = 0; i < src.cols; i++)
            for(j = 0; j < src.rows; j++){
                i1 = (i - centeri)*rotmat.at<float>(0, 0) + (j - centerj)*rotmat.at<float>(1, 0) + centeri;
                j1 = (i - centeri)*rotmat.at<float>(0, 1) + (j - centerj)*rotmat.at<float>(1, 1) + centerj;
                if(0 <= i1 && i1 < dst.cols && 0 <= j1 && j1 < dst.rows)
                    dst.at<uchar>(i1, j1) = src.at<uchar>(i, j);
            }
    }
    // 3 灰度图像滤波
    void grayFiltering(cv::Mat& src, int select=0, int filter_size=9, double Q=1){
        int m = filter_size/2;
        int n = filter_size*filter_size;
        cv::Mat src_clone = src.clone();
        for(int i=m; i < src.rows - m; i++)
            for(int j=m; j < src.cols - m; j++){ 
                cv::Mat sub_matrix = src_clone(cv::Rect(j - m, i - m, filter_size, filter_size));
                if(src.at<uchar>(i,j) == 0)
                    src.at<uchar>(i,j) = maxValueConvolution(sub_matrix, filter_size);
            }
    }
    // 3.0 最大值滤波
    int maxValueConvolution(cv::Mat& image_block, int size){
        int max = 0;
        for(int i=0; i < image_block.rows; i++)
            for(int j=0; j < image_block.cols; j++){
                if(image_block.at<uchar>(i, j) > max)
                    max = image_block.at<uchar>(i, j);
            }
        return max;
    }
    // 3.1 中值滤波
    int middleValueConvolution(cv::Mat& image_block, int size=5){
        int min = 0, k = 0, pos = size*size/2;
        std::vector<int> nums;
        for(int k1 = 0; k1 < size; k1++)
            for(int k2 = 0; k2 < size; k2++)
                nums.push_back(image_block.at<uchar>(k1,k2));
        int middle = findMiddleNum(nums, 0, size*size - 1, pos);
        return middle;
    }
    // 3.2.1 快速查找中位数
    int findMiddleNum(std::vector<int>& nums, int begin, int end, int n){
        int i = partition(nums, begin, end);
        if(i == n)
            return nums[i];
        else if(i > n)
            return findMiddleNum(nums, begin, i-1, n);
        else
            return findMiddleNum(nums, i+1, end, n);
    }
    // 3.2.2 交换
    void exchange(std::vector<int>& nums, int a,int b){
        int c = nums[a];
        nums[a] = nums[b];
        nums[b] = c;
        return;
    }
    // 3.2.2 快速查找中位数
    int partition(std::vector<int>& nums, int begin, int end){
        int i = begin, j = end + 1;
        int x = nums[begin];
        while (true) {
            while (nums[++i] < x) {// 向右扫描
                if (i == end)
                    break;
            }
            while (nums[--j] > x) {// 向左扫描
                if (j == begin)
                    break;
            }
            if (i >= j) // 指针相遇,切分位置确定
                break;
            exchange(nums, i, j);// 交换左右逆序元素
        }
        // 运行到最后:i指向从左往右第一个大于x的元素,j指向从右往左第一个小于x的元素。
        exchange(nums, begin, j);// 将切分元素放在切分位置
        return j;
    }
    //  运行
    void run(){
        RotateScalingImage(original_gray_image[0]);
    }


private:
    std::vector<cv::Mat> original_color_image;
    std::vector<cv::Mat> original_gray_image;
};

int main(){
    std::vector<std::string> path;
    path.push_back("/home/lyd/image_process/pic/lena.jpg");
    Extra1 ex6(path);
    ex6.run();

    return 1;
}

三、实验结果

数字图像处理实验(六):图像旋转与缩放

数字图像处理实验(六):图像旋转与缩放

数字图像处理实验(六):图像旋转与缩放