Java – opencv java modify pixel values

image processingjavaopencv

I've been trying to convert some opencv C++ code in opencv java and I can't seem to get pixel division to work properly. I take a meanshiftsegmented mat that I convert to grayscale then to 32F.

I then compare the most downsampled then upsampled image (which is comprised of the gray meanshift mat) to the original gray meanshift mat.

I've already read Using get() and put() to access pixel values in OpenCV for Java

however, it and others like it do not work. The error message I am getting is invalid mat type 5. However, even if I were able to see the saliency map I am positive it is wrong. This is because when I pass in image 001.jpg in c++ I am supposed to see the original image + red square around the objects. In java, I am only seeing the original image at the end.

NOTE :

AbstractImageProvider.deepCopy(AbstractImageProvider.matToBufferedImage(Saliency),disp);

Is an API call that works when I attempt to show the original mat, meanShift mat, and the gray meanShift mat. It fails at showing saliency.

c++

I only did a channel split because I was testing out other colorspaces, however in java I only want to use grayscale.

  input = MeanShift.clone();
  input.convertTo(input, CV_32F);

  for(int i = 0; i < Pyramid_Size; i++){DS_Pyramid[i] = input.clone();}

  for (int i = 0; i < Pyramid_Size; i++){ 
    for (int k = 0; k <= i; k++){ // Why don't I just downsamplex3 a copy of MeanShift.clone then upsamplex3 that same one? ...
      pyrDown (DS_Pyramid[i], DS_Pyramid[i], Size(DS_Pyramid[i].cols/2, DS_Pyramid[i].rows/2));
      US_Pyramid[i] = DS_Pyramid[i].clone();
    }
    for (int j = 0; j <= i; j++){
      pyrUp (US_Pyramid[i], US_Pyramid[i], Size(US_Pyramid[i].cols*2, US_Pyramid[i].rows*2));
    }
  }

  top = US_Pyramid[Pyramid_Size - 1].clone(); // most down sampled layer, up sampled.
  split(top, top_chs);
  split(input.clone(), meanShift_chs); // split into channels result
  split(input.clone(), sal_chs); // holder to use for compare

  float top_min = 1.0;
  float ms_min = 1.0;
  for (int i = 0; i < top.rows; i++){   // find the smallest value in both top and meanShift
    for (int k = 0; k < top.cols; k++){ // this is so you can sub out the 0 with the min value
      for (int j = 0; j < top.channels(); j++){ // later on
    float a = top_chs[j].at<float>(i,k);
    float b = meanShift_chs[j].at<float>(i,k);
    if (a < top_min && a >= 0) {top_min = a;} // make sure you don't have a top_min of zero... that'd be bad.
    if (b < ms_min && b >= 0)  { ms_min = b;}
      }
    }
  }

  for (int i = 0; i < top.rows; i++){
    for (int k = 0; k < top.cols; k++){
      for (int j = 0; j < top.channels(); j++){
    float a,b,c;
    a = top_chs[j].at<float>(i,k);
    b = meanShift_chs[j].at<float>(i,k);

    if (a <= 0){a = top_min;} // make sure you don't divide by zero
    if (b <= 0){b = ms_min;} // make sure you really don't divide by zero
    if (a <= b){c = 1.0 - a/b;}
    else {c = 1.0 - b/a;}

    // c = sqrt(c); // makes stuff more salient, but makes noise pop out too
    sal_chs[j].at<float>(i,k) = c;
      }
    }
  }
  merge(sal_chs, Saliency); // combine into saliency map
  imshow("saliency", Saliency);

java

    MeanShift = inputImage.clone();

    Imgproc.pyrMeanShiftFiltering(MeanShift, MeanShift, MeanShift_spatialRad, MeanShift_colorRad);
    Imgproc.cvtColor(MeanShift, MeanShift, Imgproc.COLOR_BGR2GRAY);

    MeanShift.convertTo(MeanShift, CvType.CV_32F);                 // 32F between 0 - 1. ************** IMPORTANT LINE

    for (int i = 0; i < PyrSize; i++){
        DS_Pyramid.add(new Mat());
        UP_Pyramid.add(new Mat());
    }

    for (int i = 0; i < PyrSize; i++){    
        DS_Pyramid.set(i, MeanShift);
    }       

    for (int i = 0; i < PyrSize; i++){
        for(int k = 0; k <= i; k++){                               // At 0 is downsampled once, second twice, third 3 times. 
        Imgproc.pyrDown(DS_Pyramid.get(i), DS_Pyramid.get(i)); // pyrDown by default img.width / 2 img height / 2
        Mat a = new Mat();                                     // save the sampled down at i
        a = DS_Pyramid.get(i);                            
        UP_Pyramid.add(a);
        }
        for (int j = 0; j <= i; j++){
        Imgproc.pyrUp(UP_Pyramid.get(i),UP_Pyramid.get(i));    
        }                                                          
    }
    top = UP_Pyramid.get(PyrSize-1);
    bot = MeanShift.clone();
    Saliency = MeanShift.clone();


    //http://answers.opencv.org/question/5/how-to-get-and-modify-the-pixel-of-mat-in-java/
    //http://www.tutorialspoint.com/java_dip/applying_weighted_average_filter.htm

    for (int i = 0; i < top.rows(); i++){
        for (int j = 0; j < top.cols(); j++){
        int index = i * top.rows() + j;

        float[] top_temp = top.get(i, j);
        float[] bot_temp  = bot.get(i,j);
        float[] sal_temp = bot.get(i,j);

        if (top_temp[0] <= bot_temp[k]){sal_temp[0] = 1.0f - (top_temp[0]/bot_temp[0]);}
        else                           {sal_temp[0] = 1.0f - (bot_temp[0]/top_temp[0]);}

        Saliency.put(i,j, sal_temp);
        }
    }

    AbstractImageProvider.deepCopy(AbstractImageProvider.matToBufferedImage(Saliency),disp);

Best Answer

Found a simple and working solution after a lot of searching. This might help you get past the error- invalid mat type 5

Code:

Mat img = Highgui.imread("Input.jpg"); //Reads image from the file system and puts into matrix
int rows = img.rows(); //Calculates number of rows
int cols = img.cols(); //Calculates number of columns
int ch = img.channels(); //Calculates number of channels (Grayscale: 1, RGB: 3, etc.)

for (int i=0; i<rows; i++)
{
    for (int j=0; j<cols; j++)
    {
        double[] data = img.get(i, j); //Stores element in an array
        for (int k = 0; k < ch; k++) //Runs for the available number of channels
        {
            data[k] = data[k] * 2; //Pixel modification done here
        }
        img.put(i, j, data); //Puts element back into matrix
    }
}
Highgui.imwrite("Output.jpg", img); //Writes image back to the file system using values of the modified matrix

Note: An important point that has not been mentioned anywhere online is that the method put does not write pixels onto Input.jpg. It merely updates the values of the matrix img. Therefore, the above code does not alter anything in the input image. For producing a visible output, the matrix img needs to be written onto a file i.e., Output.jpg in this case. Also, using img.get(i, j) seems to be a better way of handling the matrix elements rather than using the accepted solution above as this helps in visualizing and working with the image matrix in a better way and does not require a large contiguous memory allocation.