图像降采样的实现详解

此篇文章是关于图像降采样的实现,侧重点是为了详细阐述降采样的实现,而无关乎优化,代码基于OpenCV 3.2.0&&C++实现。降采样算法主要采用高斯卷积实现,卷积核采用一维卷积核:double w[5] = {1.0/4 - a/2.0, 1.0/4, a, 1.0/4, 1.0/4 - a/2.0}, 取a = 0.6,降采样主题思想如下图所示(图像从UCF大学计算机视觉课件上截取):
图像降采样的实现详解_第1张图片
图像降采样的实现详解_第2张图片

以下是代码实现:

void myPyrDown(Mat img, Mat &dst)
{
    // 降采样高斯权重
    double a = 0.6;
    double w[5] = {1.0/4 - a/2.0, 1.0/4, a, 1.0/4, 1.0/4 - a/2.0};// 这里面double类型需要1.0/4而不是1/4,我有时会疏忽这一点
    // 转换图像数据类型
    Mat src = img.clone();
    src.convertTo(src, CV_64FC1);
    // 定义目标矩阵,矩阵行列数减半向上取整(/2.0而不是/2)
    dst = Mat((int)(src.rows / 2.0 + 0.5), (int)(src.cols / 2.0 + 0.5), CV_64FC1, Scalar(0.0));
    // 定义x方向降采样临时矩阵
    Mat temp_x(src.rows, (int)(src.cols / 2.0 + 0.5), CV_64FC1, Scalar(0.0));
    // 定义x方向边界扩充,两边扩充的两列像素直接复制原图像两边缘像素
    Mat paddImg_x(src.rows, src.cols + 4, CV_64FC1, Scalar(0.0));
    for (int i = 0; i < paddImg_x.rows; ++i)
    {
        for (int j = 0; j < paddImg_x.cols; ++j)
        {
            if (j < 2)
                paddImg_x.at<double>(i, j) = src.at<double>(i, j);
            else if (j >= 2 && j < paddImg_x.cols - 2)
                paddImg_x.at<double>(i, j) = src.at<double>(i, j - 2);
            else
                paddImg_x.at<double>(i, j) = paddImg_x.at<double>(i, j - 1);
        }
    }
    // x方向降采样
    for (int i = 0; i < temp_x.rows; ++i)
    {
        for (int j = 0; j < temp_x.cols; ++j)
        {
            for (int m = -2; m <= 2; ++m)
            {
                // 权重和
                temp_x.at<double>(i, j) += w[m + 2] * paddImg_x.at<double>(i, j * 2 + m + 2);
            }
        }
    }
    // 基于已得到的temp_x,定义y方向边界扩充矩阵
    Mat paddImg_y(temp_x.rows + 4, temp_x.cols, CV_64FC1, Scalar(0.0));
    for (int i = 0; i < paddImg_y.rows; ++i)
    {
        for (int j = 0; j < paddImg_y.cols; ++j)
        {
            if (i < 2)
                paddImg_y.at<double>(i, j) = temp_x.at<double>(i, j);
            else if (i >= 2 && i < paddImg_y.rows - 2)
                paddImg_y.at<double>(i, j) = temp_x.at<double>(i - 2, j);
            else
                paddImg_y.at<double>(i, j) = paddImg_y.at<double>(i - 1, j);
        }
    }
    // y方向上的降采样
    for (int i = 0; i < dst.rows; ++i)
    {
        for (int j = 0; j < dst.cols; ++j)
        {
            for (int m = -2; m <= 2; ++m)
            {
                // 权重和
                dst.at<double>(i, j) += w[m + 2] * paddImg_y.at<double>(i * 2 + m + 2, j);
            }
        }
    }
    // 转换图像数据类型
    dst.convertTo(dst, CV_8U);
}

以下为测试代码:

#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

void myPyrDown(Mat img, Mat &dst);

int main()
{
    Mat img1 = imread("lena.tiff", IMREAD_GRAYSCALE);
    Mat img2;
    myPyrDown(img1, img2);

    imshow("img1", img1);
    imshow("img2", img2);
    waitKey(0);
    return 0;
}

以下为测试结果(图像大小为511*511):
图像降采样的实现详解_第3张图片
图像降采样的实现详解_第4张图片

你可能感兴趣的:(Computer,vision)