Chris
Chris

Reputation: 657

C++ OpenCV: Iterate through pixels in a Mat which is ROI of another Mat

I have a very large Mat which is actually a ROI of another Mat (obtained by otherMat(cv::Rect(x,y,w,h))). I want to go through all the pixels of the Mat, do some pixelwise computation and write the result to another Mat by using a pointer.

Going through all pixels, including the ones outside the ROI is working fine so far, but I am wondering what the fastest way of skipping the pixels outside the ROI is. I want to have as few cache misses as possible and also I don't want to have an inefficient branch prediction. What would be the best way to go about this?

Edit: I am not interested in getting a submatrix for a specifitc region of interest. I am interested in iterating through the pixel by pointer in an maximally efficient way without accessing data outside the submatrix' region.

Upvotes: 2

Views: 7987

Answers (2)

Micka
Micka

Reputation: 20140

Just use a submatrix:

cv::Mat largeMat
cv::Rect roi(yourROI);
cv::Mat submatrix = largeMat(roi);

// now iterate over all the pixels of submatrix

you will have cache misses at the end of each row

Here's the actual code example which shows, that the pixels outside of the submat are skipped (you'll get an additional cache miss at the end of each row but that should be all).

int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/Lenna.png");

    cv::Rect roi(128, 128, 256, 256);
    cv::Mat submat = input(roi);

    cv::MatIterator_<cv::Vec3b> it; // = src_it.begin<cv::Vec3b>();
    for (it = submat.begin<cv::Vec3b>(); it != submat.end<cv::Vec3b>(); ++it)
    {
        (*it)[0] = 0;
        (*it)[1] = 0;
    }

    cv::imshow("input", input);
    cv::imwrite("C:/StackOverflow/Output/submatIter.png", input);
    cv::waitKey(0);
    return 0;
}

giving this result:

enter image description here

If you want it a little faster you can use row-Pointers: http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html

Please mind, that in the link they compared debug mode runtime speed, that's why the random access is so slow. In release mode it should be as fast (or maybe faster) than the iterator verson. But here's the row-Ptr version (which spares to compute the row-offset on each pixel access) which gives the same result and should be the fastest way (if openCV's LUT function can't be used for your task):

int main(int argc, char* argv[])
{
    cv::Mat input = cv::imread("C:/StackOverflow/Input/Lenna.png");

    cv::Rect roi(128, 128, 256, 256);
    cv::Mat submat = input(roi);

    cv::Vec3b * currentRow;

    for (int j = 0; j < submat.rows; ++j)
    {
        currentRow = submat.ptr<cv::Vec3b>(j);
        for (int i = 0; i < submat.cols; ++i)
        {
            currentRow[i][0] = 0;
            currentRow[i][1] = 0;
        }
    }

    cv::imshow("input", input);
    cv::imwrite("C:/StackOverflow/Output/submatIter.png", input);
    cv::waitKey(0);
    return 0;
}

Upvotes: 5

Awais Rafique
Awais Rafique

Reputation: 476

As the OtherMat is a subset of Original mat and you want to do operation over the original mat but only inside the otherMat Region

//As otherMat(cv::Rect(x,y,w,h)));
for(int j=x;j<x+w;j++) 
{
  for (int i=y;i<y+h;i++)
  {  
       original.at<uchar>(j,i) = 255; 
  }
}

Upvotes: 0

Related Questions