This some parts of my opencv image processing codes.In it, I generate two dynamic arrays to store the total numbers of black points per col/row in binary image.
Here are the codes:
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImg = imread("oura.bmp");
width = srcImg.cols - 2;
height = srcImg.rows - 2;
Mat srcGrey;
Mat srcRoi(srcImg, Rect(1, 1, width, height));
cvtColor(srcRoi, srcGrey, COLOR_BGR2GRAY);
int thresh = 42;
int maxval = 255;
threshold(srcGrey, srcRoiBina, thresh, maxval, THRESH_BINARY);
int *count_cols = new int[width] ();
int *count_rows = new int[height] ();
for (int i = 0; i < width; i++)
{
cout << count_cols[i] << endl;
}
for (int i = 0; i < height; i++)
{
uchar *data = srcRoiBina.ptr<uchar>(i);
for (int j = 0; j < width; j++)
{
if (data[j] == 0)
{
count_cols[j]++;
count_rows[i]++;
}
}
}
delete[] count_cols;
delete[] count_rows;
return 0;
}
My question is that: if I use the follow codes
int *count_cols = new int[width];
int *count_rows = new int[height];
memset(count_cols, 0, sizeof(count_cols));
memset(count_rows, 0, sizeof(count_rows));
for (int i = 0; i < width; i++)
{
cout << count_cols[i] << endl;
}
to replace the corresponding codes below, why the dynamic arrays can not be initialized to zero? It seems that the memset does not work.
Platform: Visual Stdio 2013 + opencv 3.0.0
Could you please help me?
Additionally, the original image oura.bmp is 2592*1944.Thus the length of the dynamic array count_cols is 2590(ie, 2592-2). Is there some potential problems?
count_cols is of type int*, so sizeof(count_cols) will be 8 (64bit) or 4 (32bit). You'll want to use sizeof(int) * width instead (and similarly for rows).
sizeof(count_rows) is returning the size of the pointer, not the size of the array.
Use height * sizeof(int) instead. Same applies for the columns too.
Related
I have a problem with initializing a 3D Mat with openCV.
I would like to create a 3D matrix of size (rows x cols x 16), rows and cols being the dimensions of an image given earlier in the program. I tried I can not say how many different methods, and all return to me more or less the same thing: the dimensions of my matrices are worth 0 or -858993460.
My code lines :
Mat image_Conv;
int rows = imageBicubic.rows;
int cols = imageBicubic.cols;
image_Conv = Mat::zeros(rows, cols, CV_32FC(16));
Can you tell me why I have this problem? Of course I read all the posts that speak, read the doc opencv on the class Mat, but nothing works, I still have the same problem. I specify that my data in the Mat will be float.
The code :
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <ctime>
#include <iostream>
using namespace std;
//#include <opencv.hpp>
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv/highgui.h>
using namespace cv;
////////////////////////////////////////
// main file
int main()
{
string fileName = "myImage.jpg";
Mat imageSrc = cv::imread(fileName, CV_LOAD_IMAGE_UNCHANGED); // Read the file
if (!imageSrc.data) // Check for invalid input
{
cout << "Could not open or find the image\n";
return 1;
}
cout << "Loaded " << fileName << " (" << imageSrc.channels() << " channels)\n";
//int colorTransform = (imageSrc.channels() == 4) ? CV_BGRA2RGBA : (imageSrc.channels() == 3) ? CV_BGR2RGB : CV_GRAY2RGB;
//cv::cvtColor(imageSrc, imageSrc, colorTransform);
imageSrc.convertTo(imageSrc, CV_32F, 1 / 255.0, 0.0);
int SliceSizeWidth = imageSrc.cols / 2;
int sliceShiftWidth = imageSrc.cols / 4;
int sliceWidthNumber = (imageSrc.cols / sliceShiftWidth) - 1;
int SliceSizeHeight = imageSrc.rows / 2;
int sliceShiftHeight = imageSrc.rows / 4;
int sliceHeightNumber = (imageSrc.rows / sliceShiftHeight) - 1;
for (int sliceIndexHeight = 0; sliceIndexHeight < sliceHeightNumber; sliceIndexHeight++)
{
for (int sliceIndexWidth = 0; sliceIndexWidth < sliceWidthNumber; sliceIndexWidth++)
{
Mat patchImage = imageSrc(Rect(sliceIndexWidth*sliceShiftWidth, sliceIndexHeight*sliceShiftHeight, SliceSizeWidth, SliceSizeHeight));
Mat patchImageCopy;
patchImage.copyTo(patchImageCopy); // Deep copy => data are contiguous in patchImageCopy
Mat imageBicubic;
resize(patchImageCopy, imageBicubic, Size(2 * patchImage.cols, 2 * patchImage.rows), INTER_CUBIC);
Mat image_Padding;
int padding = 1;
copyMakeBorder(imageBicubic, image_Padding, padding, padding, padding, padding, BORDER_CONSTANT, Scalar(0));
Mat image_Conv;
int rows = imageBicubic.rows;
int cols = imageBicubic.cols;
image_Conv = Mat::zeros(rows, cols, CV_32FC(16));
/* rest of the code I have to write */
image_Conv.convertTo(image_Conv, CV_8U, 255.0, 0.0);
string nameBase = fileName.substr(0, fileName.find('.'));
string nameExt = fileName.substr(fileName.find('.'), fileName.length() - nameBase.length());
string strH = to_string(sliceIndexHeight);
string strW = to_string(sliceIndexWidth);
string outFileName = nameBase + "_H" + strH + "W" + strW + nameExt;
imwrite(outFileName, image_Conv);
}
}
return 0;
}
PS : Most of the code is not mine, I have to use it for my internship and can only edit between the lines :
resize(patchImageCopy, imageBicubic, Size(2 * patchImage.cols, 2 * patchImage.rows), INTER_CUBIC);
and
image_Conv.convertTo(image_Conv, CV_8U, 255.0, 0.0);
Thank you for your help !
EDIT : My first problem is solved, but it seems that it didn't work after all. I suppose that Mat::zeros set all the Mat elements at 0, right ? But if I write
cout << image_Conv.at<float>(0,0,0) << endl;
I have the error : "Unhandled exception at 0x000007FEFD4FA06D in xxxxxx.exe: Microsoft C++ exception: cv::Exception at memory location 0x000000000023E540.".
I don't know what the problem is with the memory and how to fix it.
My goal is to fill my matrix element by element thanks to several for loops which will be realized several operations, before the result is written in the element of my corresponding Mat. I did that why 3D and 4D arrays, and maybe it's the easiest solution, to do all the calculs with arrays, but I can't go from a 3D array to a 3D Mat or a 3D Mat to a 3D array.
just tested this on visual studio 2015, opencv 3.4
cv::Mat mat = cv::Mat::zeros(5, 5, CV_32FC(16));
this works fine.
You should be able to create a multi-dimensional matrix filled with 0-values using:
int size[3] = { 5, 4, 3 };
cv::Mat M(3, size, CV_32F, cv::Scalar(0));
You can iterate over the matrix with M.at(i,j,k) (only for 3D matrix created as above):
for (int i = 0; i < size[0]; i++) {
for (int j = 0; j < size[1]; j++) {
for (int k = 0; k < size[2]; k++) {
M.at<float>(i,j,k) = i*12+j*3+k;
}
}
}
for (int i = 0; i < size[0]; i++) {
for (int j = 0; j < size[1]; j++) {
for (int k = 0; k < size[2]; k++) {
std::cout << "M(" << i << ", " << j << ", " << k << "): " << M.at<float>(i,j,k) << std::endl;
}
}
}
Alternatively, you should be able to create a 2D matrix with multiple channels with:
cv::Mat M(5, 4, CV_32FC(3), cv::Scalar(0));
To iterate over the 2D matrix and over the channels:
for (int i = 0; i < M.rows; i++) {
for (int j = 0; j < M.cols; j++) {
for (int k = 0; k < M.channels(); k++) {
M.at<cv::Vec<float, 3> >(i,j)[k] = i*M.cols*M.channels()+j*M.channels()+k;
}
}
}
I am new with OpenCV. I am working on Visual Studio 2017 and use the plugin Image Watch to see Mat file of openCV.
What I've done:
I have to read a binary file to get 1000 images (256*320 pixels uint16 so 2 octets by pixel) in an array of double. After this, I wanted to see with Image Watch my data to be sure all is okay. So I convert the first image into a uchar on 8 bit to visualise it. I add my code (most part don't read it, just go to the end) :
#include "stdafx.h"
#include <iostream>
#include "stdio.h"
#include <fstream>
#include <stdint.h>
#include "windows.h"
#include <opencv2/core/core.hpp> // cv::Mat
#include <math.h>
#include <vector>
using namespace std;
using namespace cv;
template<class T>
T my_ntoh_little(unsigned char* buf) {
const auto s = sizeof(T);
T value = 0;
for (unsigned i = 0; i < s; i++)
value |= buf[i] << CHAR_BIT * i;
return value;
}
int main()
{
ifstream is("Filename", ifstream::binary);
if (is) {
// Reading size of the file and initialising variables
is.seekg(0, is.end);
int length = is.tellg();
int main_header_size = 3000;
int frame_header_size = 1000;
int width = 320, height = 256, count_frames = 1000;
int buffer_image = width * height * 2;
unsigned char *data_char = new unsigned char[length]; // Variable which will contains all the data
// Initializing 3D array for stocking all images
double ***data;
data = new double**[count_frames];
for (unsigned i = 0; i < count_frames; i++) {
data[i] = new double*[height];
for (unsigned j = 0; j < height; j++)
data[i][j] = new double[width];
}
// Reading the file once
is.seekg(0, is.beg);
is.read(reinterpret_cast<char*>(data_char), length);
// Convert pixel by pixel uchar into uint16 (using pointer on data_char)
int indice, minid = 65536.0, maxid = 0.0;
for (unsigned count = 0; count < count_frames; count++) {
// Initialize pointer address
indice = main_header_size + count * (frame_header_size + buffer_image) + frame_header_size;
for (unsigned i = 0; i < height; i++) {
for (unsigned j = 0; j < width; j++) {
data[count][i][j] = my_ntoh_little<uint16_t>(data_char + indice);
// Search for min/max for normalize after
if (data[count][i][j] < minid and count == 0)
minid = data[count][i][j];
if (data[count][i][j] > maxid and count == 0)
maxid = data[count][i][j];
// Updating pointer to next pixel
indice += 2;
}
}
}
// Get back first image, normalize between 0-255, cast into uchar to the future Mat object
uchar *dataImRGB = new uchar[width * height * 3];
int image_display = 900;
int pixel_norm;
for (unsigned i = 0; i < height; i++) {
for (unsigned j = 0; j < width; j++) {
pixel_norm = round((data[image_display][i][j] - double(minid)) / double(maxid - minid) * 255);
dataImRGB[i * 320 * 3 + 3 * j] = static_cast<uchar>(pixel_norm);
dataImRGB[i * 320 * 3 + 3 * j + 1] = static_cast<uchar>(pixel_norm);
dataImRGB[i * 320 * 3 + 3 * j + 2] = static_cast<uchar>(pixel_norm);
}
}
// Create Mat object (it is imageRGB8 I can see on Image watch)
Mat imageRGB8 = Mat(width, height, CV_8UC3, dataImRGB);
// Creating a list of Map and add first Mat
vector<Mat> listImages;
listImages.push_back(imageRGB8);
// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------
// Future : directly keep the uchar read in the original file and import it on a Mat object
// But how to get the pixel at (0,0) of the first Mat on the vector ?
// -----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------
// De-Allocate memory to prevent memory leak
for (int i = 0; i < count_frames; ++i) {
for (int j = 0; j < height; ++j)
delete[] data[i][j];
delete[] data[i];
}
delete[] data;
}
return 0;
}
Where I am stuck:
I don't know how to work with this vector, how to manipulate the data. For example, if i want to do the mean of all images, so the mean of all Mat objects in the vector, how to do this ? Or just how to get the first pixel of the third image in the vector ? These examples have for aim to explain me the slicing with such type of data because I know how it works with vector of double, but not with openCv object.
Thank you in advance for any help/advice.
Assuming that you have got all of your images properly packed into your image list you can do the following:
This will get the mean of all images in your list:
cv::Scalar meansum(0.0f,0.0f,0.0f);
size_t length = listImages.size();
for (size_t i = 0; i < length; i++){
//mu == mean of current image
cv::Scalar mu = cv::mean(listImages[i]);
meansum += mu;
}
float means[3] = { meansum[0] / length, meansum[1] / length, meansum[2] / length };
std::cout << "Means " << means[0] << " " << means[1] << " " << means[2] << std::endl;
To get the first pixel in your third image you can use the at() method or a row pointer. (Row pointers are faster, but don't have any guards against accessing out of bounds memory locations.)
Mat third_image = list_images[2];
//using at()
uchar first_pixel_blue_value = third_image.at<uchar>(0,0,0);
std::cout<<(int)first_pixel_blue_value<<std::endl;
//using row pointer
uchar* row = third_image.ptr<uchar>(0); //pointer to row 0
std::cout<<"blue: " <<(int)row[0];
std::cout<<" green: "<<(int)row[1];
std::cout<<" red: " <<(int)row[2];
More info can be found here:
https://docs.opencv.org/3.1.0/d2/de8/group__core__array.html (under functions)
and here:
https://docs.opencv.org/trunk/d3/d63/classcv_1_1Mat.html
I am currently working on imaging processing using arrays to store R,G,B values from a 24 bit BITMAP image of width 120 and height 100 pixels.
Visual Studio 2010 is being used.
I have currently extracted the individual R,G,B values into three separate2D arrays from the 24 bit bitmap (it is assumed correct as the correct R,G,B values have been written to a text file with the right pixel count as well).
These individual R,G,B values need to be restored back into an array (either 1D or 2D), which is then written to an image file. The output should be identical to the original image.
I have tried the following but the output is currently incorrect (same width, height and memory size but colouring is incorrect).
Appreciate your guidance and feedback.
#include <iostream>
#include <fstream>
#include <windows.h>
#include <WinGDI.h>
unsigned char** Allocate2DArray(int w, int h)
{
unsigned char ** buffer = new unsigned char * [h]; // allocate the rows
unsigned char * memory_pool = new unsigned char [w*h]; // allocate memory pool
for (int i = 0; i < h; ++i)
{
buffer[i] = memory_pool; // point row pointer
memory_pool += w; // go to next row in memory pool
}
return buffer;
}
void DeAllocate2DArray(unsigned char** buffer)
{
delete [] buffer[0]; // delete the memory pool
delete [] buffer; // delete the row pointers
}
using namespace std;
int main()
{
const int width = 120;
const int height = 100;
int bytesPerPixel = 3;
unsigned char m_cHeaderData[54];
unsigned char** m_cImageData = new unsigned char* [height];
for( int i = 0; i <height; i++)
{
m_cImageData[i] = new unsigned char [width*bytesPerPixel];
}
ifstream* m_pInFile;
m_pInFile = new ifstream;
m_pInFile->open("image.bmp", ios::in | ios::binary);
m_pInFile->seekg(0, ios::beg);
m_pInFile->read(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
m_pInFile->read(reinterpret_cast<char*>(m_cImageData[i]), width*bytesPerPixel);
}
m_pInFile->close();
// Declare a pointer of the type you want.
// This will point to the 1D array
unsigned char* array_1D;
array_1D = new unsigned char[height*width*bytesPerPixel];
if(array_1D == NULL) return 0; // return if memory not allocated
// Copy contents from the existing 2D array
int offset = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offset = width * bytesPerPixel* j;
for(int i=0; i<width*bytesPerPixel; i++) // traverse width
{
array_1D[offset + i] = m_cImageData[j][i];
// update value at current (i, j)
}
}
// Declare three 2D arrays to store R,G, and B planes of image.
unsigned char**arrayR_2D, **arrayG_2D, **arrayB_2D;
arrayR_2D = Allocate2DArray(width, height);
arrayG_2D = Allocate2DArray(width, height);
arrayB_2D = Allocate2DArray(width, height);
// return if memory not allocated
if(arrayR_2D == NULL || arrayG_2D == NULL || arrayB_2D == NULL) return 0;
// Extract R,G,B planes from the existing composite 1D array
ofstream RGBdata2D;
RGBdata2D.open("RGBdata2D.txt");
int pixelCount = 0;
int offsetx = 0;
int counter = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offsetx = width * j * bytesPerPixel;
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
arrayB_2D[j][counter] = array_1D[offsetx + i+0];
arrayG_2D[j][counter] = array_1D[offsetx + i+1];
arrayR_2D[j][counter] = array_1D[offsetx + i+2];
RGBdata2D<<"B: "<< (int)arrayB_2D[j][counter] << " G: " << (int)arrayG_2D[j][counter] << " R: " << (int)arrayR_2D[j][counter]<< endl;
pixelCount++;
++counter;
}
counter = 0;
}
RGBdata2D<<"count of pixels: "<< pixelCount << endl;
RGBdata2D.close();
//put RGB from 2D array contents back into a 1D array
offset = 0;
counter = 0;
for(int j=0; j<height; j++) // traverse height (or rows)
{
offset = width * bytesPerPixel * j;
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter++];
array_1D[offset + i+1] = arrayG_2D[j][counter++];
array_1D[offset + i+2] = arrayR_2D[j][counter++];
}
counter = 0;
}
ofstream* m_pOutFileRGB;
m_pOutFileRGB = new ofstream;
m_pOutFileRGB->open("imageCopyRGB.bmp", ios::out | ios::trunc | ios::binary);
m_pOutFileRGB->write(reinterpret_cast<char*>(m_cHeaderData), 54);
for(int i = 0; i <height; i++)
{
m_pOutFileRGB->write(reinterpret_cast<char*>(array_1D), width*bytesPerPixel);
}
m_pOutFileRGB->close();
// After complete usage, delete the memory dynamically allocated
DeAllocate2DArray(arrayR_2D);
DeAllocate2DArray(arrayG_2D);
DeAllocate2DArray(arrayB_2D);
// After complete usage, delete the memory dynamically allocated
delete[] array_1D; //delete the pointer to pointer
for(int i = 0; i <height; i++)
{
delete[] m_cImageData[i];
}
delete[] m_cImageData;
system("pause");
return 0;
}
I didn't test by myself, but at this point
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter++];
array_1D[offset + i+1] = arrayG_2D[j][counter++];
array_1D[offset + i+2] = arrayR_2D[j][counter++];
}
You inclement counter too many times, and it may lead to incorrect result.
Instead, try this:
for(int i=0; i<width*bytesPerPixel; i+=bytesPerPixel) // width
{
array_1D[offset + i+0] = arrayB_2D[j][counter];
array_1D[offset + i+1] = arrayG_2D[j][counter];
array_1D[offset + i+2] = arrayR_2D[j][counter];
counter++;
}
I wish to find number of white pixels in every row of binary image. And if that count is greater than 90, I wish to delete the entire row by changing each pixel value in that row to 0. The code that I wrote is not working. And apparently, I am getting the same binary image at output.
Please help me out in fixing the problem. BTW, am using openCV 2.0.
using namespace std;
double a = 15;
double b = 255;
Mat I1;
int main(int argv, char **argc)
{
cv: Mat I = imread("abc.bmp");
if (I.empty())
{
std::cout << "!!! Failed imread(): image not found" << std::endl;
}
threshold(I, I1, a, b, THRESH_BINARY);
int r = I.rows;
int c = I.cols;
for (int j = 0; j < r; j++)
{
int count = 0;
for (int i = 0; i < c; i++)
{
if (I1.at<uchar>(j, i) == 255)
count = count + 1;
}
if (count > 90)
{
for (int i = 0; i < c; i++)
I1.at<uchar>(j, i) = 0;
}
}
namedWindow("Display window", 0);// Create a window for display.
imshow("Display window", I1);
waitKey(0);
return 0;
}
By default imread returns 3 channel BGR image. If you want to load grayscale/binary image use cv::IMREAD_GRAYSCALE parameter:
cv::Mat I = cv::imread("abc.bmp", cv::IMREAD_GRAYSCALE);
I am implementing a Kuwahara filter in C++, with OpenCV to help opening and displaying images. The idea is quite straight forward but somehow I got weird result from it. Here' the cose:
#include "opencv2/opencv.hpp"
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
using namespace cv;
//This class is essentially a struct of 4 Kuwahara regions surrounding a pixel, along with each one's mean, sum and variance.
class Regions{
int* Area[4];
int Size[4];
unsigned long long Sum[4];
double Var[4];
int kernel;
public:
Regions(int _kernel) : kernel(_kernel) {
for (int i = 0; i<4; i++) {
Area[i] = new int[kernel*kernel];
Size[i] = 0;
Sum[i] = 0;
Var[i] = 0.0;
}
}
//Update data, increase the size of the area, update the sum
void sendData(int area, int data){
Area[area][Size[area]] = data;
Sum[area] += data;
Size[area]++;
}
//Calculate the variance of each area
double var(int area) {
int __mean = Sum[area]/Size[area];
double temp = 0;
for (int i = 0; i<Size[area]; i++) {
temp+= (Area[area][i] - __mean) * (Area[area][i] - __mean);
}
if (Size[area]==1) return 1.7e38; //If there is only one pixel inside the region then return the maximum of double
//So that with this big number, the region will never be considered in the below minVar()
return sqrt(temp/(Size[area]-1));
}
//Call the above function to calc the variances of all 4 areas
void calcVar() {
for (int i = 0; i<4; i++) {
Var[i] = var(i);
}
}
//Find out which regions has the least variance
int minVar() {
calcVar();
int i = 0;
double __var = Var[0];
if (__var > Var[1]) {__var = Var[1]; i = 1;}
if (__var > Var[2]) {__var = Var[2]; i = 2;}
if (__var > Var[3]) {__var = Var[3]; i = 3;}
return i;
}
//Return the mean of that regions
uchar result(){
int i = minVar();
return saturate_cast<uchar> ((double) (Sum[i] *1.0 / Size[i]));
}
};
class Kuwahara{
private:
int wid, hei, pad, kernel;
Mat image;
public:
Regions getRegions(int x, int y){
Regions regions(kernel);
uchar *data = image.data;
//Update data for each region, pixels that are outside the image's boundary will be ignored.
//Area 1 (upper left)
for (int j = (y-pad >=0)? y-pad : 0; j>= 0 && j<=y && j<hei; j++)
for (int i = ((x-pad >=0) ? x-pad : 0); i>= 0 && i<=x && i<wid; i++) {
regions.sendData(1,data[(j*wid)+i]);
}
//Area 2 (upper right)
for (int j = (y-pad >=0)? y-pad : 0; j<=y && j<hei; j++)
for (int i = x; i<=x+pad && i<wid; i++) {
regions.sendData(2,data[(j*wid)+i]);
}
//Area 3 (bottom left)
for (int j = y; j<=y+pad && j<hei; j++)
for (int i = ((x-pad >=0) ? x-pad : 0); i<=x && i<wid; i++) {
regions.sendData(3,data[(j*wid)+i]);
}
//Area 0 (bottom right)
for (int j = y; j<=y+pad && j<hei; j++)
for (int i = x; i<=x+pad && i<wid; i++) {
regions.sendData(0,data[(j*wid)+i]);
}
return regions;
}
//Constructor
Kuwahara(const Mat& _image, int _kernel) : kernel(_kernel) {
image = _image.clone();
wid = image.cols; hei = image.rows;
pad = kernel-1;
}
//Create new image and replace its pixels by the results of Kuwahara filter on the original pixels
Mat apply(){
Mat temp;
temp.create(image.size(), CV_8U);
uchar* data = temp.data;
for (int j= 0; j<hei; j++) {
for (int i = 0; i<wid; i++)
data[j*wid+i] = getRegions(i,j).result();
}
return temp;
}
};
int main() {
Mat img = imread("limes.tif", 1);
Mat gray, dest;
int kernel = 15;
gray.create(img.size(), CV_8U);
cvtColor(img, gray, CV_BGR2GRAY);
Kuwahara filter(gray, kernel);
dest = filter.apply();
imshow("Result", dest);
imwrite("result.jpg", dest);
waitKey();
}
And here's the result:
As you can see it's different from the correct result, the borders of those limes seem to be duplicated and moved upward. If I apply a 15x15 filter, it gives me a complete mess like this:
I've spent my whole day to debug, but so far nothing is found. I even did the calculation on small images by hand and compare with the result and see no differences.
Could anyone help me find out what did I do wrong?
Many many thanks.
It turns out that there's nothing wrong with my code, but the way I defined a kernel was the source of problem. My kernel is actually one of four small kuwahara sections, while the correct definition of a kernel is the whole area where data is calculated for each pixel, therefore the area that contains all four sections is actually the kernel. So when talked about a 7x7 "kernel", I actually applied a 15x15 one, and the horrible result came not from a 15x15 kernel as I thought, but from a 31x31. At that size, Kuwahara filter simply doesn't make sense and bizarre results are inevitable.