If your image has no non-black outlier (like noise) you can ignore the canny and the findContours and instead just create the bounding rect from all non-black pixel locations:
int main()
{
cv::Mat in = cv::imread("CropWhite.jpg");
// vector with all non-black point positions
std::vector<cv::Point> nonBlackList;
nonBlackList.reserve(in.rows*in.cols);
// add all non-black points to the vector
//TODO: there are more efficient ways to iterate through the image
for(int j=0; j<in.rows; ++j)
for(int i=0; i<in.cols; ++i)
{
// if not black: add to the list
if(in.at<cv::Vec3b>(j,i) != cv::Vec3b(0,0,0))
{
nonBlackList.push_back(cv::Point(i,j));
}
}
// create bounding rect around those points
cv::Rect bb = cv::boundingRect(nonBlackList);
// display result and save it
cv::imshow("found rect", in(bb));
cv::imwrite("CropWhiteResult.png", in(bb));
cv::waitKey(-1);
return 0;
}
don't know whether there are more efficient ways to create the vector, given in openCV, but this should still be much faster than canny and findContours.
with this input:
I get this result:
there are some areas around the contour, because you provided a jpg image, where the borders of the contour aren't true black because of compression, I guess.