Ask Your Question

resistor's profile - activity

2013-03-03 19:51:08 -0600 asked a question Access of reduced image vectors

Hi All,

I am a newbie in OPENCV and tried to the similar things (discard margin sizes and compute for the effective width and height for a scanned document image) like the MATLAB code below

MATLAB CODE
====================================================================     
[height, width] = size(img_input);
img_colsum = sum(img_input,1);
idx_col_nonzero = find(img_colsum ~= 0);
img_width_effective = width+idx_col_nonzero(1)-idx_col_nonzero(end);    
img_rowsum = sum(img_input,2);    
idx_row_nonzero = find(img_rowsum ~= 0);
img_height_effective = height+idx_row_nonzero(1)-idx_row_nonzero(end);

I faced the difficulty of using the OEPNCV cv::reduce function, and probably also the way to access its elements. The strange thing that I saw in my following c++ code is that it works for one case but fails to work to the other case.

int find_idx_nonzero(cv::Mat &vec_input, cv::Mat &vec_idx) {
    int width = vec_input.cols;
    int height = vec_input.rows;
    int idx = 0;
    if (height == 1) {
        for (int w=0; w<width; w++) {
             if ( vec_input.at<float>(0,w) != 0 ) { vec_idx.at<int>(0,idx) = w; idx++; }
        }
    }
    else if (width == 1) {
        for (int h=0; h<height; w++) {
             if ( vec_input.at<float>(h,0) != 0 ) { vec_idx.at<int>(idx,0) = h; idx++; }
        }
    }
    return idx;
}

int main() {
    cv::Mat img_input; img_input = cv::imread("inputDoc.tif");
    int width = img_input.cols;
    int height = img_input.rows;
    cv::Mat img_colsum, img_rowsum;
    cv::reduce( img_input, img_colsum, 0, CV_REDUCE_SUM, CV_64FC1 );
    cv::Mat idx_col_nonzero( 1, width, CV_64F );
    int col_length;
    col_length = find_idx_nonzero( img_colsum, idx_col_nonzero );
    int img_width_effective = width+idx_col_nonzero.at<int>(0,0)-idx_col_nonzero.at<int>(0,col_length-1);
    cv::reduce( img_input, img_rowsum, 1, CV_REDUCE_SUM, CV_64FC1 );
    cv::Mat idx_row_nonzero( height, 1, CV_64F );
    int row_length;
    row_length = find_idx_nonzero( img_rowsum, idx_row_nonzero );
    int img_height_effective = height+idx_row_nonzero.at<int>(0,0)-idx_roonzero.at<int>(row_length-1,0);
    return 1;
}

And I have the following questions

 1. why does this code work OK for the column case but not the row case?   
 2. why *matrix.at(idx)* fails to work when I replace those matrix.at(0,idx) and (idx,0)? I saw [the OPENCV tutorial](http://opencv.jp/opencv-2.2_org/cpp/core_basic_structures.html?highlight=iterator#cv-mat-at) said that when a matrix is of 1D, then one can simply access the matrix element via *matrix.at(idx)*, instead of *matrix.at(idx,0)* or *matrix.at(0,idx)*. I tried this technique, but it does not work.
 3. Is there any quick rule of thumb to determine the data type in **.at<data type>**, especially I donot know in what situation to use what data type. For example, in the above code if I use *val_idx.at<float>(idx,0)* instead, the answer turns to be wrong, but I donot know why... 
 4. Why the size of img_rowsum and img_colsum are 1D, but I output them using cout<< img_colsum <<endl; I saw the output data is of the format like [0,0,0,1,0,2,...]?
 5. If I transpose the img_rowsum vector (i.e. only use the upper branch in if-else), I got the right answer.

Sorry for too many questions. Any comments are welcome