Ask Your Question
0

Euclidean Distance between Matrix Channels

asked 2014-11-06 17:08:03 -0600

matt.hammer gravatar image

updated 2014-11-07 00:43:00 -0600

berak gravatar image

I am working on background subtraction in OpenCV Android/Java. I need to find the Euclidean distance between two RGB images. First, I subtract the two images from each other, element-by-element.

Then I use this function:

private Mat euclidChannels(Mat in){
    Core.pow(in, 2, in);
    int rows = in.rows();
    Mat out = new Mat(new Size(in.cols(), in.rows()), CvType.CV_32F);
    Core.reduce(in.reshape(1,in.rows() * in.cols()), out, 1, Core.REDUCE_SUM);
    Core.sqrt(out.reshape(1, rows), out);
    return out;
}

based on the following technique: how to sum a 3 channel matrix to a one channel matrix?

I get the error:

11-06 22:45:02.094: E/cv::error()(10655): OpenCV Error: Unsupported format or combination of formats (Unsupported combination of input and output array formats) in void cv::reduce(cv::InputArray, cv::OutputArray, int, int, int), file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/core/src/matrix.cpp, line 2365

So I chased it down in the c++ source:

1921            if(op == CV_REDUCE_SUM)
1922            {
1923                if(sdepth == CV_8U && ddepth == CV_32S)
1924                    func = reduceC_<uchar,int,OpAdd<int> >;
1925                if(sdepth == CV_8U && ddepth == CV_32F)
1926                    func = reduceC_<uchar,float,OpAdd<int> >;
1927                if(sdepth == CV_8U && ddepth == CV_64F)
1928                    func = reduceC_<uchar,double,OpAdd<int> >;
1929                if(sdepth == CV_16U && ddepth == CV_32F)
1930                    func = reduceC_<ushort,float,OpAdd<float> >;
1931                if(sdepth == CV_16U && ddepth == CV_64F)
1932                    func = reduceC_<ushort,double,OpAdd<double> >;
1933                if(sdepth == CV_16S && ddepth == CV_32F)
1934                    func = reduceC_<short,float,OpAdd<float> >;
1935                if(sdepth == CV_16S && ddepth == CV_64F)
1936                    func = reduceC_<short,double,OpAdd<double> >;
1937                if(sdepth == CV_32F && ddepth == CV_32F)
1938                    func = reduceC_<float,float,OpAdd<float> >;
1939                if(sdepth == CV_32F && ddepth == CV_64F)
1940                    func = reduceC_<float,double,OpAdd<double> >;
1941                if(sdepth == CV_64F && ddepth == CV_64F)
1942                    func = reduceC_<double,double,OpAdd<double> >;
1943            }
...
1964        if( !func )
1965            CV_Error( CV_StsUnsupportedFormat,
1966            "Unsupported combination of input and output array formats" );

I think this means that none of those if statements are hitting. But, I dumped the depths of the source and destination matrices and I get 0 & 5 respectively, which should correspond to CV_8U & CV_32F (checks out in both Java and C++ source code) - and hit on line 1925 of the source.

Any ideas as to what I'm doing wrong?

(I know my listing line numbers don't match the line numbers in the error message, but the listing is all I could find on the web: matrix.cpp

edit retag flag offensive close merge delete

Comments

1

stop coding for a moment (it's all broken in the most horrible way), and have a look at the builtin http://docs.opencv.org/java/org/opencv/video/BackgroundSubtractorMOG2.html

berak gravatar imageberak ( 2014-11-07 02:07:13 -0600 )edit

Thanks for the link - while that's what I'll probably end up using, I'd like to learn more about what's going on under the hood.

matt.hammer gravatar imagematt.hammer ( 2014-11-07 11:37:48 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2014-11-07 11:44:12 -0600

matt.hammer gravatar image

Still not sure why the original code didn't hit that if-statement. A type change and a memory leak later, I got it to work:

private void euclidChannels(Mat in, Mat out){       
    in.convertTo(rgbF, CvType.CV_32F);
    Core.pow(rgbF, 2, rgbF);
    rgbF = rgbF.reshape(1,rgbF.rows() * rgbF.cols());
    Core.reduce(rgbF, gF, 1, Core.REDUCE_SUM);          
    // fix rgbF - constant time
    rgbF = rgbF.reshape(3, in.rows());              
    gF = gF.reshape(1, this.height);            
    Core.sqrt(gF, gF);                  
    gF.convertTo(out, CvType.CV_8UC1);      
}

Re-reshaping the rgbF matrix back to it's original state was key to eliminating the memory leak, as apparently convertTo() will re-allocate the destination matrix if it doesn't like the one you provide. (I guess I could have added another temp matrix instead, but reshape() is supposed to be constant time, so might as well save a bit of memory)

edit flag offensive delete link more

Question Tools

Stats

Asked: 2014-11-06 17:08:03 -0600

Seen: 1,414 times

Last updated: Nov 07 '14