Ask Your Question

# C++ Sort Array and Create Matrix

A while back I followed a tutorial (or maybe an answer from another question or something) on how to apply an oil painting filter (http://jsfiddle.net/loktar/96arS/) to an image and write it to a canvas using javascript. Now I want to achieve the same effect using openCV and C++.

I was also using: http://supercomputingblog.com/graphic... as a reference for the psuedo-code.

So far I am as far as reading the image and iterating through the pixels and finding the intensity values.

int main()
{
Mat im = imread(...);
Mat outline;
Mat paint;

int intensityLUT[im.rows][im.cols];
int rgbLUT[im.rows][im.cols]; //r/g/b
int intensity = 20;
int radius = 3;
int pixelIntensityValue;
int pixelIntensityCount;

for(int y = 0; y < im.rows; y++)
{
for (int x = 0; x < im.cols; x++)
{
int r = im.at<cv::Vec3b>(y,x);
int g = im.at<cv::Vec3b>(y,x);
int b = im.at<cv::Vec3b>(y,x);

intensityLUT[y][x] = round(  ((r+g+b)/3)  * intensity/255);

rgbLUT[y][x] = r;
rgbLUT[y][x] = g;
rgbLUT[y][x] = b;

}
} //first itteration to get rgb values

for(int y = 0; y < im.rows; y++)
{
for (int x = 0; x < im.cols; x++) //for each pixel
{
for(int yy = -radius; yy <= radius; yy++)
{
for(int xx = -radius; xx <= radius; xx++)
{
if(y + yy > 0 && y+yy < im.rows && x+xx > 0 && x+xx < im.cols)
{
int intensityVal = intensityLUT[y+yy][x+xx];
pixelIntensityCount[intensityVal] ++; // priority
pixelIntensityCount[intensityVal] += rgbLUT[y+yy][x+xx]; //red
pixelIntensityCount[intensityVal] += rgbLUT[y+yy][x+xx]; //green
pixelIntensityCount[intensityVal] += rgbLUT[y+yy][x+xx]; //blue

}
//
//pixelIntensityCount.sort(function (a, b)
//{
//return b.val - a.val;
//});

//var curMax = pixelIntensityCount.val,
//dIdx = (y*w+x) * 4;

//destPixData[dIdx] = ~~ (pixelIntensityCount.r / curMax);
//destPixData[dIdx+1] = ~~ (pixelIntensityCount.g / curMax);
//destPixData[dIdx+2] = ~~ (pixelIntensityCount.b / curMax);
//destPixData[dIdx+3] = 255;
}
}
//imshow("Result", paint);
waitKey();
return 0;
}


so the part I'm stuck on is converting the array sort function and then creating a new matrix to store the image for showing / writing at the end. I think apart from that it should work? Can anyone suggest to me, the correct way to do that please?

Thanks.

edit retag close merge delete

## Comments

1

sidenote: int intensityLUT[im.rows][im.cols]; -- this is using a gcc specific extension, and is not portable.

Sorry what do you mean by this? is it fixed if I'm using Mat intensityLUT(im.rows,im.cols,CV_8UC1); as per the example below?

yes, it is solved by using a cv::Mat. above, you're trying to make a dynamic array in auto memory, this is usually not allowed, only like int arr; , where the size is known at compile time.

## 1 answer

Sort by » oldest newest most voted

New answer much faster...

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/videoio/videoio.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>
#include <fstream>
#include <algorithm>
#include <ctype.h>

using namespace cv;
using namespace std;

class ParallelInPaint: public ParallelLoopBody
{
private:
Mat &imgSrc;
Mat &dst;
Mat &intensityLUT;
bool verbose;
int radius;
int intensity;

public:
ParallelInPaint(Mat& img, Mat &d,Mat &iLuminance,int r):
imgSrc(img),
dst(d),
intensityLUT(iLuminance),
radius(r),
verbose(false)
{}
void Verbose(bool b){verbose=b;}
virtual void operator()(const Range& range) const
{

int width = imgSrc.cols;
if (verbose)
cout << getThreadNum()<<"# :Start from row " << range.start << " to "  << range.end-1<<" ("<<range.end-range.start<<" loops)" << endl;
vector<int> pixelIntensityCount;
vector<Vec3f> pixelIntensityRGB;

for(int y = range.start; y < range.end; y++)
{
Vec3b *vDst = (Vec3b *)dst.ptr(y);
for (int x = 0; x < imgSrc.cols; x++,vDst++) //for each pixel
{
pixelIntensityCount.assign(256,0);
pixelIntensityRGB.assign(256,Vec3f(0,0,0));
for(int yy = -radius; yy <= radius; yy++)
{
Vec3b *vPtr = (Vec3b *)imgSrc.ptr(y+yy)+x-radius;
uchar *uc=intensityLUT.ptr(y+yy)+x-radius;
for(int xx = -radius; y + yy >= 0 && y+yy < imgSrc.rows && xx <= radius; xx++,vPtr++,uc++)
{
if( x+xx >= 0 && x+xx < imgSrc.cols)
{
int intensityVal = *uc;
pixelIntensityCount[intensityVal]++; // priority
pixelIntensityRGB[intensityVal] += *vPtr; //red

}
}
}
vector<int>::iterator it;
int pos = distance(pixelIntensityCount.begin(),max_element(pixelIntensityCount.begin(),pixelIntensityCount.end()));
*vDst = pixelIntensityRGB[pos]/pixelIntensityCount[pos];

}
}

}
ParallelInPaint& operator=(const ParallelInPaint &) {
return *this;
};
};

int main(int argc, char* argv[])
{
VideoCapture v(0);
Mat im;
v>>im;
Mat  intensityLUT(im.rows,im.cols,CV_8UC1);
Mat  rgbLUT(im.rows,im.cols,CV_8UC3); //r/g/b
Mat dst(im.rows,im.cols,CV_8UC3);
int intensity = 20;
int radius = 3;

while (true)
{

v>>im;

cvtColor(im,intensityLUT,CV_RGB2GRAY);
intensityLUT = intensityLUT *(intensity/255.);

ParallelInPaint x(im,dst,intensityLUT,radius);
parallel_for_(Range(0,im.rows), x,getNumThreads());
imshow("Result", dst);
char c= waitKey(1);
switch (c){
case 'I':
intensity++;
if (intensity>255)
intensity=255;
break;
case 'i':
intensity--;
if (intensity==0)
intensity=1;
case 'R':
radius++;
if (radius>255)
radius=255;
break;
case 'r':
radius--;
if (radius==-1)
radius=0;
}
if (c>32)
cout << "Intensity =" << intensity << "\tradius = " << radius << "\n";
}
return 0;
}


You should use opencv function for color conversion. There is no opimization and it is not vey fast... (Check conversion int to float)

int main(int argc, char* argv[])
{
Mat im=imread("Forest.jpg");
Mat dst(im.rows,im.cols,CV_8UC3);

Mat  intensityLUT(im.rows,im.cols,CV_8UC1);
Mat  rgbLUT(im.rows,im.cols,CV_8UC3); //r/g/b
int intensity = 20;
int radius = 3;
int pixelIntensityValue;
Vec3f pixelIntensityRGB;

cvtColor(im,intensityLUT,CV_RGB2GRAY);
intensityLUT = intensityLUT *(intensity/255.);

for(int y = 0; y < im.rows; y++)
{
for (int x = 0; x < im.cols; x++) //for each pixel
{
vector<int> pixelIntensityCount;
vector<Vec3f> pixelIntensityRGB;
pixelIntensityCount.assign(100,0);
pixelIntensityRGB.assign(100,Vec3f(0,0,0));
for(int yy = -radius; yy <= radius; yy++)
{
for(int xx = -radius; xx <= radius; xx++)
{
if(y + yy > 0 && y+yy < im.rows && x+xx > 0 && x+xx < im.cols)
{
int ...
more

Official site

GitHub

Wiki

Documentation

## Stats

Asked: 2016-03-31 10:17:51 -0500

Seen: 1,399 times

Last updated: Apr 02 '16