2

I am trying to sort pixel values of an image (example 80x20) from lowest to highest.

Below is the some code:

bool sortPixel(int first, int second)
{
    return (first < second);
}

    vector<int>vect_sortPixel;
    for(int y=0; y<height; y++)
    {
        for(int x=0; x<width; x++)
        {
            vect_sortPixel.push_back(cvGetReal2D(srcImg, y, x));
            sort(vect_sortPixel.begin(), vect_sortPixel.end(), sortPixel);
        }
    }

But it takes quite long time to compute. Any suggestion to reduce the processing time? Thank you.

ArtemStorozhuk
  • 8,715
  • 4
  • 35
  • 53
Mzk
  • 1,102
  • 3
  • 17
  • 40
  • Can you add code for the `sort()` method? – Alex W Jun 23 '12 at 04:13
  • i'm sorry. the sort is called from (algorithm.h) – Mzk Jun 23 '12 at 04:18
  • what about using `sort` function in OpenCV? http://docs.opencv.org/modules/core/doc/operations_on_arrays.html?highlight=sort#sort – Abid Rahman K Jun 23 '12 at 04:26
  • But it stated "If you want to sort matrix rows or columns lexicographically, you can use STL std::sort generic function with the proper comparison predicate." – Mzk Jun 23 '12 at 04:49

2 Answers2

1

Don't use getReal2D. It's quite slow.

Convert image to cv::Mat or Mat. Use its data pointer to get the pixel values. Mat.data() will give you pointer to the original matrix. Use that.

And as far as sorting is concerned, I would advise you to first make an array of all the pixels, then sort it using Merge sort (time complexity O(n log n))

#include<opencv2/highgui/highgui.hpp>
#include<stdio.h>
using namespace cv;
using namespace std;
int main()
{
    Mat img = imread("filename.jpg",CV_LOAD_IMAGE_COLOR);
    unsigned char *input = (unsigned char*)(img.data);
    int i,j,r,g,b;
    for(int i = 0;i < img.cols;i++){
            for(int j = 0;j < img.rows;j++){
                b = input[img.cols * j + i] ;
                g = input[img.cols * j+ i + 1];
                r = input[img.cols *j + i +2];
            }
        }
    return 0;
}

Using this you can access pixel values from the main matrix.

Warning: This is not how you compare it. I'm suggesting that by using something like this, you can access pixel values.

Mat.data() gives you pointer to the original matrix. This matrix is a 1 D matrix with all the given pixel values.

Image => (x,y,z),(x1,y1,z1), etc..

Mat(original matrix) => x,y,z,x1,y1,z1,...

If you still have some doubts regarding how to extract data from Mat, visit this link OpenCV get pixel channel value from Mat image

and here's a link regarding Merge Sort http://www.cplusplus.happycodings.com/Algorithms/code17.html

Community
  • 1
  • 1
Froyo
  • 17,947
  • 8
  • 45
  • 73
  • How can I do that? Can you give me some example? – Mzk Jun 23 '12 at 05:23
  • @Mizuki [Wikipedia's Merge Sort](http://en.wikipedia.org/wiki/Merge_sort) article has some pseudocode. Personally I'd use a Radix or Quick sort, since they're generally faster, although they are more complex to code. Unless your images are really massive though, merge sort should be fine. – William Lawn Stewart Jun 23 '12 at 06:33
  • where can I find the Radiz or Quick Sort? Is it available? Thank you for your information. It helps a lot. – Mzk Jun 23 '12 at 07:33
  • @MizukiKai there's `qsort` in STL. Just google it. And I already told you that `sort` should work fast. Have you done all steps I told you? I'm 100% sure that after doing it your algorithm will be very fast. – ArtemStorozhuk Jun 23 '12 at 07:51
  • @Froyo this is also a bit slow beceause you use two cycles instead one and `img.cols * j` takes a lot time. Also you even didn't test it because it crashes at first iteration `input[-1] = ?` – ArtemStorozhuk Jun 23 '12 at 09:14
  • I didn't mean to take this loop. I just suggested that you can access pixel values in this way. sorry if it's misleading. I'll edit. – Froyo Jun 23 '12 at 09:36
  • 1
    So why did you adit your message? Before editing: `Use its data pointer to get the pixel values. Mat.data() will give you pointer to the original matrix. Use that.` Isn't it a suggestion??? – ArtemStorozhuk Jun 23 '12 at 09:48
  • No. It's still there. see. I just suggested him how to use Mat.data – Froyo Jun 23 '12 at 09:53
  • Why don't you answer my question? – ArtemStorozhuk Jun 24 '12 at 07:40
  • I haven't removed that statement. It's there. Please see the answer again. – Froyo Jun 24 '12 at 09:20
1

There are few problems in your code:

  • As Froyo already said you use cvGetReal2D which is actually not very fast. You have to convert your cvMat to cv::Mat. To do this there's cv::Mat constructor:
// converts old-style CvMat to the new matrix; the data is not copied by default
Mat(const CvMat* m, bool copyData=false);

And after this use direct pixels acces as mentioned in this SO question.

  • Another problem is that you use push_back which actually also not very fast. You know the size of array, so why don't you allocate needed memory at the beginning? Like this:

vector<int> vect_sortPixel(mat.cols*mat.rows);

And than just use vect_sortPixel[i] to get needed pixel.

  • Why do you call sort in the loop? You have to call it after loop, when array is already created! Default STL's sort should work fast:

Complexity

Approximately N*logN comparisons on average (where N is last-first). In the worst case, up to N^2, depending on specific sorting algorithm used by library implementation.

Community
  • 1
  • 1
ArtemStorozhuk
  • 8,715
  • 4
  • 35
  • 53
  • Thanks for the information. I kinda know what to do next. It helps. – Mzk Jun 23 '12 at 07:34
  • How can I get the pixel just by using vect_sortPixel[i]? I need to push back first right? – Mzk Jun 24 '12 at 02:19
  • 1
    @MizukiKai no! I already told you that `push_back` is slow operation. If you know size of array than it makes sense to allocate needed memory in vector constructor. Do you know what do words `allocate` and `constructor` mean? If no than read [this article](http://www.cplusplus.com/reference/stl/vector/vector/). – ArtemStorozhuk Jun 24 '12 at 07:39