Ask Your Question
1

C++ Sort Array and Create Matrix

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

AlecTheLion gravatar image

updated 2016-04-15 09:31:47 -0500

LBerger gravatar image

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][3]; //r/g/b
    int intensity = 20;
    int radius = 3;
    int pixelIntensityValue[100];
    int pixelIntensityCount[100][4];

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

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

            rgbLUT[y][x][0] = r;
            rgbLUT[y][x][1] = g;
            rgbLUT[y][x][2] = 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][0] ++; // priority
                        pixelIntensityCount[intensityVal][1] += rgbLUT[y+yy][x+xx][0]; //red
                        pixelIntensityCount[intensityVal][2] += rgbLUT[y+yy][x+xx][1]; //green
                        pixelIntensityCount[intensityVal][3] += rgbLUT[y+yy][x+xx][2]; //blue

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

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

             //destPixData[dIdx] = ~~ (pixelIntensityCount[0].r / curMax);
             //destPixData[dIdx+1] = ~~ (pixelIntensityCount[0].g / curMax);
             //destPixData[dIdx+2] = ~~ (pixelIntensityCount[0].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 flag offensive close merge delete

Comments

1

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

berak gravatar imageberak ( 2016-04-01 01:32:04 -0500 )edit

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?

AlecTheLion gravatar imageAlecTheLion ( 2016-04-01 07:01:41 -0500 )edit

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[10]; , where the size is known at compile time.

berak gravatar imageberak ( 2016-04-01 07:59:42 -0500 )edit

1 answer

Sort by ยป oldest newest most voted
2

answered 2016-03-31 14:36:15 -0500

LBerger gravatar image

updated 2016-04-02 07:49:40 -0500

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[100];
    Vec3f pixelIntensityRGB[100];

    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)
edit flag offensive delete link more

Comments

This is really amazing! thank you so much for your help.

AlecTheLion gravatar imageAlecTheLion ( 2016-04-04 05:13:37 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

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

Seen: 1,142 times

Last updated: Apr 02 '16