Проблема при копировании Opencv Image в больший - PullRequest
0 голосов
/ 04 марта 2020

Я пытаюсь скопировать изображение OpenCV в увеличенное изображение, но у меня возникают некоторые проблемы. Я хочу создать увеличенное изображение с рамкой определенного размера c, но я не хочу менять эту границу. Итак, я хотел бы изменить только центральную часть изображения с таким же размером. Вот код, который я использую.

main. cpp

#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;
}

function

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;
}

Вот входное изображение, которое я использую. enter image description here Вот пример изображения, которое я получаю в результате. Padded_Image

Я сделал несколько других примеров, используя вектор, и результат кажется правильным, так что не так с этим кодом?

Заранее спасибо.

1 Ответ

0 голосов
/ 05 марта 2020

Единственная проблема, которую я могу найти, это в случае, если kernel.rows или kernel.cols даже .

Размер вашего выходного изображения (image.rows + kernel.rows-1, image.cols + kernel.cols-1).
Размер будет слишком маленьким, если kernel.rows или kernel.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 применяется cols и y применяется 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<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;
}

край:
enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...