Problem while copying an Opencv Image into a bigger one - c++

I'm trying to copy an OpenCV image into a bigger image, but I'm getting some problems. I want to create a bigger image that has a border of an specific size but I do not want to change that border. So, I'd like to change just the center part of the image with the same size of it.
Here is the code I'm using.
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;
}
Here is the input image that I'm using.
Here is an example of image that I'm getting as a result.
I have done some other examples using vector and the result seems correct, so what is wrong with that code?
Thanks in advance.

The only issue I could find is in case kernel.rows or kernel.cols are even.
The size of your output image is (image.rows + kernel.rows-1, image.cols + kernel.cols-1).
Size is going to be too small when kernel.rows or kernel.cols are even.
For example: in case kernel.rows = 0, the size of the output is going to be smaller than the input.
Suggested correction:
cv::Mat image_padded(image.rows + (kernel.rows/2)*2, image.cols + (kernel.cols/2)*2, image.type());
Dividing the (integer) value by 2 and then multiply be 2 covers both even and odd cases.
Note about naming conversions:
The naming convention is: x applies cols, and y applies rows.
You have replaced the names, and made code reading difficult.
I am not sure if your issue is related to the problem I found.
It could also be a problem in the input or output (problem in the code parts you are not showing).
Here is a test sample code (I put some of your code in comments):
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;
}
Update
After posting your main, the problem can be found:
You are using at<double>, but image type is uchar (one byte per pixel).
Solution:
Replace at<double> with at<uchar> when reading from and writing to image.
Keep at<double> for the kernel, because the kernel type is double.
Here is the modified testing code (just for reference):
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;
}
edge:

Related

How to implement convolution Gaussian blur without padding using OpenCV in C++

I am implementing convolution Gaussian blur with OpenCV without using OpenCV functions, but my code is programmed with padding.
Now I want to remove the padding from the matrix so that my code can be executed without the matrix with padding. How can I modify the code below to do so?
class Filteration {
private:
// member function to pad the image before convolution
Mat padding(Mat img, int k_width, int k_height, string type)
{
Mat scr;
img.convertTo(scr, CV_64FC1);
int pad_rows, pad_cols;
pad_rows = (k_height - 1) / 2;
pad_cols = (k_width - 1) / 2;
Mat pad_image(Size(scr.cols + 2 * pad_cols, scr.rows + 2 * pad_rows), CV_64FC1,
Scalar(0));
scr.copyTo(pad_image(Rect(pad_cols, pad_rows, scr.cols, scr.rows)));
// mirror padding
if (type == "mirror")
{
for (int i = 0; i < pad_rows; i++)
{
scr(Rect(0, pad_rows - i, scr.cols, 1)).copyTo(pad_image(Rect(pad_cols,
i, scr.cols, 1)));
scr(Rect(0, (scr.rows - 1) - pad_rows + i, scr.cols,
1)).copyTo(pad_image(Rect(pad_cols,
(pad_image.rows - 1) - i, scr.cols, 1)));
}
for (int j = 0; j < pad_cols; j++)
{
pad_image(Rect(2 * pad_cols - j, 0, 1,
pad_image.rows)).copyTo(pad_image(Rect(j, 0, 1, pad_image.rows)));
pad_image(Rect((pad_image.cols - 1) - 2 * pad_cols + j, 0, 1,
pad_image.rows)).
copyTo(pad_image(Rect((pad_image.cols - 1) - j, 0, 1,
pad_image.rows)));
}
return pad_image;
}
// replicate padding
else if (type == "replicate")
{
for (int i = 0; i < pad_rows; i++)
{
scr(Rect(0, 0, scr.cols, 1)).copyTo(pad_image(Rect(pad_cols, i, scr.cols,
1)));
scr(Rect(0, (scr.rows - 1), scr.cols, 1)).copyTo(pad_image(Rect(pad_cols,
(pad_image.rows - 1) - i, scr.cols, 1)));
}
for (int j = 0; j < pad_cols; j++)
{
pad_image(Rect(pad_cols, 0, 1, pad_image.rows)).copyTo(pad_image(Rect(j,
0, 1, pad_image.rows)));
pad_image(Rect((pad_image.cols - 1) - pad_cols, 0, 1, pad_image.rows)).
copyTo(pad_image(Rect((pad_image.cols - 1) - j, 0, 1,
pad_image.rows)));
}
// zero padding
return pad_image;
}
else
{
return pad_image;
}
}
// member function to define kernels for convolution
Mat define_kernel(int k_width, int k_height, string type)
{
// box kernel
if (type == "box")
{
Mat kernel(k_height, k_width, CV_64FC1, Scalar(1.0 / (k_width * k_height)));
return kernel;
}
// gaussian kernel
else if (type == "gaussian")
{
// I will assume k = 1 and sigma = 1
int pad_rows = (k_height - 1) / 2;
int pad_cols = (k_width - 1) / 2;
Mat kernel(k_height, k_width, CV_64FC1);
for (int i = -pad_rows; i <= pad_rows; i++)
{
for (int j = -pad_cols; j <= pad_cols; j++)
{
kernel.at<double>(i + pad_rows, j + pad_cols) = exp(-(i*i + j*j) /
2.0);
}
}
kernel = kernel / sum(kernel);
return kernel;
}
}
public:
// member function to implement convolution
void convolve(Mat scr, Mat &dst, int k_w, int k_h, string paddingType, string
filterType)
{
Mat pad_img, kernel;
pad_img = padding(scr, k_w, k_h, paddingType);
kernel = define_kernel(k_w, k_h, filterType);
Mat output = Mat::zeros(scr.size(), CV_64FC1);
for (int i = 0; i < scr.rows; i++)
{
for (int j = 0; j < scr.cols; j++)
{
output.at<double>(i, j) = sum(kernel.mul(pad_img(Rect(j, i, k_w,
k_h)))).val[0];
}
}
output.convertTo(dst, CV_8UC1); //IplImage: IPL_DEPTH_8U Mat: CV_8UC1, CV_8UC2,
CV_8UC3, CV_8UC4
}
};
int main(){
Mat img, dst;
//
Load the image
img = imread("mrl.jpg", 0);
Mat kernel;
int k_w = 5; // kernel width
int k_h = 5; // kernel height
Filteration F1;
F1.convolve(img, dst, k_w, k_h, "gaussian", "box");
namedWindow("dst", WINDOW_AUTOSIZE);
imshow("dst", dst);
waitKey(0);
}

OpenCV HLS Sharpening

I'm trying to make the Sharpening of an Image in HLS format.
I've done the Blurring correctly, but the Sharpening doesn't work.
I know the Sharpening is:
1) Blur the Image: Image -> Blurred. 2) Make Unsharp Mask: Unsharp_Mask = Image - Blurred. 3) Sharpen the Image: Sharpened = Image + Unsharp_Mask
Also I know in HLS you don't have to do this in every channel, but just in the "L" one.
I did it, but it doesn't work.
This is my code (i can't use the "code" button cause it gives me error - says that there are parts of the code that are not properly formatted as code):
// UNSHARP MASK HLS Mat* UnsharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type()); Mat* SharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
for (int i = 0; i < ImageHLS.rows; i++) {
for (int j = 0; j < ImageHLS.cols; j++)
{
UnsharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] - PaddedHLS->at<Vec3b>(i + 1, j + 1)[1];
SharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] + (UnsharpHLS->at<Vec3b>(i + 1, j + 1)[1]);
} }
cvtColor(*SharpHLS, Sharpened, COLOR_HLS2BGR);
Let's assume the previous part of the code works (I don't get any error and I've already tryed it), the only problem is in the mentioned code.
This is the whole code:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cstdlib>
#include <math.h>
using namespace cv;
using namespace std;
int main()
{
// CARICAMENTO IMMAGINE
Mat Original = imread("Lena.png", IMREAD_COLOR);
// VERIFICA SE L'IMMAGINE E' STATA LETTA CORRETTAMENTE, IN CASO CONTRARIO RITORNA -1
if (Original.empty())
{
return -1;
}
// CONVERSIONE COLORI
Mat ImageHLS;
Mat ImageRGB;
Mat Blurred;
Mat Sharpened;
cvtColor(Original, ImageRGB, COLOR_BGR2RGB);
cvtColor(Original, ImageHLS, COLOR_BGR2HLS);
// CREAZIONE IMMAGINE HLS PADDED
int FilterSize = 3;
int Padding = FilterSize - 1;
Mat* PaddedHLS = new Mat(ImageHLS.rows + Padding, ImageHLS.cols + Padding, ImageHLS.type());
copyMakeBorder(ImageHLS, *PaddedHLS, Padding / 2, Padding / 2, Padding / 2, Padding / 2, BORDER_DEFAULT);
// BLURRING SU IMMAGINE HLS PADDED
Mat* Filter = new Mat(FilterSize, FilterSize, ImageHLS.type());
for (int i = 1; i < PaddedHLS->rows - 1; i++)
{
for (int j = 1; j < PaddedHLS->cols - 1; j++)
{
for (int x = 0; x < FilterSize; x++)
{
for (int y = 0; y < FilterSize; y++)
{
Filter->at<Vec3b>(x, y)[1] = PaddedHLS->at<Vec3b>(i - 1 + x, j - 1 + y)[1];
}
}
PaddedHLS->at<Vec3b>(i, j)[1] = mean(*Filter).val[1];
}
}
cvtColor(*PaddedHLS, Blurred, COLOR_HLS2BGR);
// UNSHARP MASK HLS
Mat* UnsharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
Mat* SharpHLS = new Mat(PaddedHLS->rows, PaddedHLS->cols, PaddedHLS->type());
for (int i = 0; i < ImageHLS.rows; i++)
{
for (int j = 0; j < ImageHLS.cols; j++)
{
UnsharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] - PaddedHLS->at<Vec3b>(i + 1, j + 1)[1];
SharpHLS->at<Vec3b>(i+1, j+1)[1] = ImageHLS.at<Vec3b>(i, j)[1] + (UnsharpHLS->at<Vec3b>(i + 1, j + 1)[1]);
}
}
cvtColor(*SharpHLS, Sharpened, COLOR_HLS2BGR);
// VISUALIZZAZIONE IMMAGINI
imshow("Originale", Original);
imshow("Image RGB", ImageRGB);
imshow("Image HLS", ImageHLS);
imshow("Blurred HLS", *PaddedHLS);
imshow("Blurred BGR", Blurred);
imshow("Unsharp HLS", *UnsharpHLS);
imshow("Sharpened HLS", *SharpHLS);
imshow("Sharpened BGR", Sharpened);
//CHIUDI TUTTO
waitKey(0);
destroyAllWindows();
}

Warp Image by Diagonal Sine Wave

I'm trying to warp colour image using sin function in OpenCV and I was successful in doing so. However, how can I make a 'diagonal' warping using sine wave?
My code is this:
Mat result = src.clone();
for (int i = 0; i < src.rows; i++) { // to y
for (int j = 0; j < src.cols; j++) { // to x
for (int ch = 0; ch < 3; ch++) { // each colour
int offset_x = 0;
int offset_y = (int)(25.0 * sin(3.14 * j / 150));
if (i + offset_y < src.rows) {
result.at<Vec3b>(i, j)[ch] = src.at<Vec3b>((i + offset_y) % src.rows, j)[ch];
}
else
result.at<Vec3b>(i, j)[ch] = 0.0;
}
}
}
imshow("result", result);
How can I do this? Not drawing a sine graph, but warping an image.
Solved this! Several times ago, I've received a message by someone who told me that the image is stolen. It was from Google, actually, but I've deleted it to fulfill not to cause any situations. Thx!
I think it should look like this:
void deform()
{
float alpha = 45 * CV_PI / 180.0; // wave direction
float ox = cos(alpha);
float oy = sin(alpha);
cv::Mat src = cv::imread("F:/ImagesForTest/lena.jpg");
for (int i = 0; i < src.rows; i+=8)
{
cv::line(src, cv::Point(i, 0), cv::Point(i, src.rows),cv::Scalar(255,255,255));
}
for (int j = 0; j < src.cols; j += 8)
{
cv::line(src, cv::Point(0,j), cv::Point(src.cols,j), cv::Scalar(255, 255, 255));
}
cv::Mat result = src.clone();
for (int i = 0; i < src.rows; i++)
{ // to y
for (int j = 0; j < src.cols; j++)
{ // to x
float t =(i * oy)+ (j * ox); // wave parameter
for (int ch = 0; ch < 3; ch++)
{ // each colour
int offset_x =ox* (int)(25.0 * (sin(3.14 * t/ 150)));
int offset_y =oy* (int)(25.0 * (sin(3.14 * t / 150)));
if (i + offset_y < src.rows && j + offset_x < src.rows && i + offset_y >=0 && j + offset_x>=0)
{
result.at<cv::Vec3b>(i, j)[ch] = src.at<cv::Vec3b>(i + offset_y, j + offset_x )[ch];
}
else
result.at<cv::Vec3b>(i, j)[ch] = 0.0;
}
}
}
cv:: imshow("result", result);
cv::imwrite("result.jpg", result);
cv::waitKey();
}
The result:
BTW, may be better to use cv::remap ?

Error during convolution of image with a filter in opencv c++

I am new to opencv c++ .I am getting error with code for convolution (got from internet)which is equivalent to conv2 in matlab. The problem is all the pixel values are becoming 255.The filter which i am using in the code has same size as image. Can anybody please help me in correcting the problem.My opencv c++ code is given below:
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<stdio.h>
#include<iostream>
#include<math.h>
#include<cv.hpp>
using namespace cv;
using namespace std;
Mat gd,img,bimgFiltered,gimgFiltered,rimgFiltered,fin_img;
Mat b,g,r,cr,cb,cg,B,G,R;
Mat b_logplane, b_plane,b_logfiltered,b_log,g_logplane,g_plane,g_logfiltered;
Mat g_log,r_logplane,r_plane,r_logfiltered,r_log;
Mat kernel, dest;
int m,n,m1,m2,n1,n2;
int c = 120;
double mysum = 0.0, mysum1 = 0.0, k = 0;
int cent=0,radius=0;
enum ConvolutionType {
/* Return the full convolution, including border */
CONVOLUTION_FULL,
/* Return only the part that corresponds to the original image */
CONVOLUTION_SAME,
/* Return only the submatrix containing elements that were not influenced
by the border
*/
CONVOLUTION_VALID
};
void conv2(const Mat &img, const Mat& kernel, ConvolutionType type,Mat& dest)
{
Mat source = img;
if(CONVOLUTION_FULL == type)
{
source = Mat();
const int additionalRows = kernel.rows - 1, additionalCols = kernel.cols - 1;
copyMakeBorder(img, source, (additionalRows + 1) / 2, additionalRows / 2,
(additionalCols + 1) / 2, additionalCols / 2, BORDER_CONSTANT, Scalar(0));
}
flip(kernel, kernel, -1);
Point anchor(kernel.cols - kernel.cols / 2 - 1, kernel.rows - kernel.rows / 2 - 1);
int borderMode = BORDER_CONSTANT;
filter2D(source, dest, img.depth(), kernel, anchor, 0, borderMode);
if(CONVOLUTION_VALID == type)
{
dest = dest.colRange((kernel.cols - 1) / 2, dest.cols - kernel.cols /
2).rowRange((kernel.rows - 1) / 2, dest.rows - kernel.rows / 2);
}
}
int main()
{
img = imread("milla.bmp", CV_LOAD_IMAGE_COLOR);
b.create(img.size(),img.type());
g.create(img.size(),img.type());
r.create(img.size(),img.type());
cr.create(img.size(),img.type());
cg.create(img.size(),img.type());
cb.create(img.size(),img.type());
Mat planes[3];
split(img,planes);
bimgFiltered.create(img.size(),img.type());
gimgFiltered.create(img.size(),img.type());
rimgFiltered.create(img.size(),img.type());
dest.create(img.size(), img.type());
gd.create(img.size(), img.type());
for(int j = 0; j < img.rows; j++)
{
for(int i = 0; i < img.cols; i++)
{
radius = ((cent - i)^2 + (cent - j)^2);
gd.at<float>(j, i) = exp((-(radius) / c^2));
mysum = mysum + gd.at<float>(j, i);
}
mysum1 = mysum1 + mysum;
}
k=1/mysum1;
cout<<endl<<k<<"\n"<<endl;
for(int j = 0; j < img.rows; j++)
{
for(int i = 0; i < img.cols; i++)
{
gd.at<float>(j, i) = k * gd.at<float>(j, i);
}
}
planes[0].convertTo(planes[0],CV_32F,1.0/255.0);
planes[1].convertTo(planes[1],CV_32F,1.0/255.0);
planes[2].convertTo(planes[2],CV_32F,1.0/255.0);
conv2(planes[0],gd,CONVOLUTION_SAME,bimgFiltered);
conv2(planes[1],gd,CONVOLUTION_SAME,gimgFiltered);
conv2(planes[2],gd,CONVOLUTION_SAME,rimgFiltered);
imshow("img",gimgFiltered );
waitKey(0);
return 0;
}
There are a few problems with the code:
Issue 1:
In the following two lines:
radius = ((cent - i)^2 + (cent - j)^2);
gd.at<float>(j, i) = exp((-(radius) / c^2));
You are using ^ operator which is the bitwise XOR operator in C/C++. I think you are mistaking it for power operator. To take the power of a number you have to use the pow function as follows:
radius = powf((cent - i),2) + powf((cent - j),2);
gd.at<float>(j, i) = expf((-(radius) / (c*c)));
Issue 2:
The gd matrix is assumed to have floating point values as it is accessed like gd.at<float>(j, i), but it is declared with the same type as that of the image, i.e. CV_8UC3. So gd should be created as follows:
gd.create(img.size(), CV_32FC1);
Issue 3:
Another possible logical error may be present in the first nested loop. You may have to set mysum = 0; before starting the inner loop like this:
for(int j = 0; j < img.rows; j++)
{
mysum = 0;
for(int i = 0; i < img.cols; i++)
{
radius = powf((cent - i),2) + powf((cent - j),2);
gd.at<float>(j, i) = expf((-(radius) / (c*c)));
mysum = mysum + gd.at<float>(j, i);
}
mysum1 = mysum1 + mysum;
}
Issue 4:
Output filtered images should be created single channel instead of 3 channels:
bimgFiltered.create(img.size(),CV_8UC1);
gimgFiltered.create(img.size(),CV_8UC1);
rimgFiltered.create(img.size(),CV_8UC1);

Histogram of oriented gradiants

For a project I'm writing some code to compute the HoG of some images, but I'm stuck with the fact that my orientations are only between 0 ~ 90 degrees, while using the atan2 function.
I'm guessing that this problem occurs due to the filter2D function of OpenCV but I'm not sure if this is the reason or that I'm doing something else wrong:
Vector<Vector<Mat_<float>>> HoG(Mat image) {
Mat img_x;
Mat img_y;
IplImage img = image;
Mat kern_x = (Mat_<char>(1, 3) << -1, 0, 1);
Mat kern_y = (Mat_<char>(3, 1) << -1, 0, 1);
filter2D(image, img_x, image.depth(), kern_x);
filter2D(image, img_y, image.depth(), kern_y);
Vector<Vector<Mat_<float>>> histograms;
for(int y = 0; y < image.rows - size; y += size) {
Vector<Mat_<float>> temp_hist;
for(int x = 0; x < image.cols - size; x += size) {
float total_mag = 0;
Mat hist = Mat::zeros(1, 8, CV_32FC1);
for(int i = y; i < y + size; ++i) {
for(int j = x; j < x + size; ++j) {
float grad_x = (float)img_x.at<uchar>(i, j);
float grad_y = (float)img_y.at<uchar>(i, j);
double ori = myatan2(grad_x, grad_y);
float mag = sqrt(pow(grad_x, 2) + pow(grad_y, 2));
int bin = round(ori/45);
hist.at<float>(0, (bin - 1 < 0 ? 7 : bin - 1)) += - (float)(ori - ((round(ori/45) - 1) * 45.0 + 22.5)) / 45.0f;
hist.at<float>(0, bin) += -(float)(ori - ((round(ori/45) - 1) * 45.0 + 22.5)) / 45.0f;
total_mag += mag;
}
}
// Normalize the histogram
for(int i = 0; i < 8; ++i) {
hist.at<float>(0, i) = hist.at<float>(0, i) / total_mag;
}
temp_hist.push_back(hist);
}
histograms.push_back(temp_hist);
}
return histograms;
}
If you have any other tips to increase a speed-up in my code or something else that is also welcome of course.
I notice this:
float grad_x = (float)img_x.at<uchar>(i, j);
float grad_y = (float)img_y.at<uchar>(i, j);
You seem to be using uchar. Should this not be char?