繁体   English   中英

将 Opencv 图像复制到更大的图像时出现问题

[英]Problem while copying an Opencv Image into a bigger one

我正在尝试将 OpenCV 图像复制到更大的图像中,但遇到了一些问题。 我想创建一个具有特定尺寸边框的更大图像,但我不想更改该边框。 所以,我只想改变图像的中心部分,使其具有相同的大小。 这是我正在使用的代码。

主程序

#include <iostream>
#include "useful_tools.h"

int main()
{
    Useful_Tools ut;

    cv::Mat image = cv::imread("/home/felippe/Codigos_Cpp/Image_Registration_2D/square_landscape.jpeg");
    cv::Mat gray_image(image.rows, image.cols, image.type());
    cv::cvtColor(image, gray_image, cv::COLOR_BGR2GRAY);

    cv::Mat sobel_x(3, 3, CV_64F);

    //Filling the Sobel Filter
    sobel_x.at<double>(0, 0) = -1;
    sobel_x.at<double>(0, 1) = -2;
    sobel_x.at<double>(0, 2) = -1;
    sobel_x.at<double>(1, 0) =  0;
    sobel_x.at<double>(1, 1) =  0;
    sobel_x.at<double>(1, 2) =  0;
    sobel_x.at<double>(2, 0) =  1;
    sobel_x.at<double>(2, 1) =  2;
    sobel_x.at<double>(2, 2) =  1;

    cv::Mat edge = ut.correlation(gray_image, sobel_x, "zeros");

    return 0;
}

功能

cv::Mat PadImage(cv::Mat image, int k_cols, int k_rows)
{
    //There is an error when k_rows or k_rows are even numbers.
    //cv::Mat image_padded(image.rows + k_rows - 1, image.cols + k_cols - 1, image.type());

    //Fixing:
    cv::Mat image_padded(image.rows + (k_rows/2)*2, image.cols + (k_cols/2)*2, image.type());
    image_padded = 0;

    //if (!padding_type.compare("zeros"))
    //{

    //Naming conventions are: x applies cols, and y applies rows
    //int x_add = k_rows / 2, y_add = k_cols / 2;

    int y_add = k_rows / 2, x_add = k_cols / 2;

    for (int i = y_add; i < image.rows + y_add; i++)
        for (int j = x_add; j < image.cols + x_add; j++)
            image_padded.at<double>(i, j) = image.at<double>(i - y_add, j - x_add);
    //}

    return image_padded;
}

cv::Mat Useful_Tools::correlation(cv::Mat image, cv::Mat kernel, std::string padding_type)
{
    cv::Mat image_padded(image.rows + kernel.rows-1, image.cols + kernel.cols-1, image.type());
    image_padded = 0;
    cv::Mat result(image.rows, image.cols, image.type());
    result = 0;

    cv::Mat image_padded2 = PadImage(image, 3, 3);

    showImage(image, "Original Image");
    showImage(image_padded2, "Image Padded");

    if (!padding_type.compare("zeros"))
    {
        int x_add = kernel.rows/2, y_add = kernel.cols/2;
        for (int i = x_add; i < image.rows + x_add; i++)
            for (int j = y_add; j < image.cols + y_add; j++)
                image_padded.at<double>(i, j) = image.at<double>(i-x_add, j-y_add);
    }
    /*else if (!padding_type.compare("repeat"))
    {
        cv::Mat result(image.rows + kernel.rows/2, image.cols + kernel.cols/2, image.type());

        for (int i = (kernel.rows-1)/2; i < image.rows + (kernel.rows-1)/2; i++)
            for (int j = (kernel.cols-1)/2; j < image.cols + (kernel.cols-1)/2; j++)
                result.at<double>(i, j) = image.at<double>(i-(kernel.rows-1)/2, j-((kernel.cols-1)/2));
    }*/
    else if (!padding_type.compare("without"))
    {
        image_padded.release();
        cv::Mat image_padded = image;
    }
    else
        std::cerr << "Please enter with a valid padding value." << std::endl;

    //showImage(image_padded, "Testing Padding");
    cv::imwrite( "Padding_image.jpg", image_padded);
    for (int i = 0; i < result.rows; i++)
        for (int j = 0; j < result.cols; j++)
            for (int m = 0; m < kernel.rows; m++)
                for (int n = 0; n < kernel.cols; n++)
                {
                    std::cout << image_padded.at<double>(i+m+kernel.rows/2, j+n+kernel.cols/2) << std::endl
                              << kernel.at<double>(m, n) << std::endl;
                    result.at<double>(i, j) += image_padded.at<double>(i+m+kernel.rows/2, j+n+kernel.cols/2)*kernel.at<double>(m, n);
                    std::cout << std::endl;
                }

    return result;
}

这是我正在使用的输入图像。 在此处输入图片说明 这是我得到的一个图像示例。填充图像

我已经使用 vector 做了一些其他的例子,结果似乎是正确的,那么这段代码有什么问题呢?

提前致谢。

我能找到的唯一问题是如果kernel.rowskernel.cols偶数

输出图像的大小是(image.rows + kernel.rows-1, image.cols + kernel.cols-1)
kernel.rowskernel.cols为偶数时,大小将太小。

例如:如果kernel.rows = 0 ,输出的大小将小于输入的大小。

建议更正:

cv::Mat image_padded(image.rows + (kernel.rows/2)*2, image.cols + (kernel.cols/2)*2, image.type());

将(整数)值除以 2 然后乘以 2 涵盖偶数和奇数情况。


  • 关于命名转换的注意事项:命名约定是: x应用colsy应用rows
    您已经替换了名称,并使代码阅读变得困难。

我不确定您的问题是否与我发现的问题有关。
它也可能是输入或输出中的问题(您未显示的代码部分中的问题)。

这是一个测试示例代码(我将您的一些代码放在注释中):

cv::Mat PadImage(cv::Mat image, int k_cols, int k_rows)
{
    //There is an error when k_rows or k_rows are even numbers.
    //cv::Mat image_padded(image.rows + k_rows - 1, image.cols + k_cols - 1, image.type());

    //Fixing:
    cv::Mat image_padded(image.rows + (k_rows/2)*2, image.cols + (k_cols/2)*2, image.type());
    image_padded = 0;

    //if (!padding_type.compare("zeros"))
    //{

    //Naming conventions are: x applies cols, and y applies rows
    //int x_add = k_rows / 2, y_add = k_cols / 2;

    int y_add = k_rows / 2, x_add = k_cols / 2;

    for (int i = y_add; i < image.rows + y_add; i++)
        for (int j = x_add; j < image.cols + x_add; j++)
            image_padded.at<double>(i, j) = image.at<double>(i - y_add, j - x_add);
    //}

    return image_padded;
}


int main()
{
    //Read input image as Grayscale (one byte per pixel).
    cv::Mat Iu8 = cv::imread("img.png", cv::IMREAD_GRAYSCALE);

    //Draw a white rectangle around the input image (for testing)
    cv::rectangle(Iu8, cv::Rect(0, 0, Iu8.cols - 1, Iu8.rows - 1), cv::Scalar(255), 1);

    cv::Mat I;
    Iu8.convertTo(I, CV_64FC1); //Convert from uint8 to double

    //Execute padding function
    cv::Mat J = PadImage(I, 101, 0);

    cv::Mat Ju8;
    J.convertTo(Ju8, CV_8UC1);  //Convert from double to uint8

    //Display input and output
    cv::imshow("Iu8", Iu8);
    cv::imshow("Ju8", Ju8);
    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

更新

发布您的main ,可以发现问题:

您正在使用at<double> ,但图像类型是uchar (每像素一个字节)。

解决方案:

  • 读取和写入图像时,将at<double>替换at<double> at<uchar>
  • 内核保持at<double> ,因为内核类型是double

下面是修改后的测试代码(仅供参考):

cv::Mat correlationPad(cv::Mat image, cv::Mat kernel, std::string padding_type)
{
    cv::Mat image_padded(image.rows + kernel.rows - 1, image.cols + kernel.cols - 1, image.type());
    image_padded = 0;
    cv::Mat result(image.rows, image.cols, image.type());
    result = 0;

    //cv::Mat image_padded2 = PadImage(image, 3, 3);

    //showImage(image, "Original Image");
    //showImage(image_padded2, "Image Padded");

    if (!padding_type.compare("zeros"))
    {
        int x_add = kernel.rows / 2, y_add = kernel.cols / 2;
        for (int i = x_add; i < image.rows + x_add; i++)
            for (int j = y_add; j < image.cols + y_add; j++)
                image_padded.at<uchar>(i, j) = image.at<uchar>(i - x_add, j - y_add);
    }
    /*else if (!padding_type.compare("repeat"))
    {
        cv::Mat result(image.rows + kernel.rows/2, image.cols + kernel.cols/2, image.type());

        for (int i = (kernel.rows-1)/2; i < image.rows + (kernel.rows-1)/2; i++)
            for (int j = (kernel.cols-1)/2; j < image.cols + (kernel.cols-1)/2; j++)
                result.at<double>(i, j) = image.at<double>(i-(kernel.rows-1)/2, j-((kernel.cols-1)/2));
    }*/
    else if (!padding_type.compare("without"))
    {
        //image_padded.release();
        //cv::Mat image_padded = image;
    }
    else
        std::cerr << "Please enter with a valid padding value." << std::endl;

    //showImage(image_padded, "Testing Padding");
    //cv::imwrite("Padding_image.jpg", image_padded);
    //for (int i = 0; i < result.rows; i++)
    //    for (int j = 0; j < result.cols; j++)
    //        for (int m = 0; m < kernel.rows; m++)
    //            for (int n = 0; n < kernel.cols; n++)
    //            {
    //                std::cout << image_padded.at<double>(i + m + kernel.rows / 2, j + n + kernel.cols / 2) << std::endl
    //                    << kernel.at<double>(m, n) << std::endl;
    //                result.at<double>(i, j) += image_padded.at<double>(i + m + kernel.rows / 2, j + n + kernel.cols / 2)*kernel.at<double>(m, n);
    //                std::cout << std::endl;
    //            }

    return image_padded;
}



int main()
{
    //Read input image as Grayscale (one byte per pixel).
    cv::Mat image = cv::imread("square_landscape.jpeg");
    cv::Mat gray_image(image.rows, image.cols, image.type());
    cv::cvtColor(image, gray_image, cv::COLOR_BGR2GRAY);

    //Draw a white rectangle around the input image (for testing)
    //cv::rectangle(gray_image, cv::Rect(0, 0, gray_image.cols - 1, gray_image.rows - 1), cv::Scalar(255), 1);

    cv::Mat sobel_x(3, 3, CV_64F);

    //Filling the Sobel Filter
    sobel_x.at<double>(0, 0) = -1;
    sobel_x.at<double>(0, 1) = -2;
    sobel_x.at<double>(0, 2) = -1;
    sobel_x.at<double>(1, 0) = 0;
    sobel_x.at<double>(1, 1) = 0;
    sobel_x.at<double>(1, 2) = 0;
    sobel_x.at<double>(2, 0) = 1;
    sobel_x.at<double>(2, 1) = 2;
    sobel_x.at<double>(2, 2) = 1;

    cv::Mat edge = correlationPad(gray_image, sobel_x, "zeros");

    cv::imwrite("edge.jpg", edge);  //Save result.

    //Display input and output
    cv::imshow("gray_image", gray_image);
    cv::imshow("edge", edge);
    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

边缘:
在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM