Единственная проблема, которую я могу найти, это в случае, если 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;
}
край: