0

I am creating a stitching program and it works well. My next task is to crop the image so the image doesn't get too large and only contains the stitched areas. I am able to crop the image using the threshold() and findContours() functions. I then parse through the contours to determine where to crop. Another issue I wish to tackle in this function is to set the background to be transparent or alpha(255). My logic is take the base image to crop and do this step in conjunction with finding the area to crop. My code follows with portions that were taken from these two resources:

http://answers.opencv.org/question/37441/how-to-set-transparent-background-to-grabcut-output-image-in-opencv-c/

http://answers.opencv.org/question/24463/how-to-remove-black-background-from-grabcut-output-image-in-opencv-android/#24508

Mat crop(Mat image){
Mat cropped, grayed, thresh, transparent, result;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
int largest_contour_index=0;
int largest_area=0;
Mat alpha(image.size(),CV_8UC1,Scalar(0));

cvtColor(image, grayed, CV_BGR2GRAY);
threshold( grayed, thresh, 1, 255,THRESH_BINARY);
findContours( thresh, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

vector<int> x,y;
for(int i=0; i < contours.size(); i++){
    for(int j = 0; j < contours.at(i).size();j++){
        double a=contourArea( contours[i],false);  //  Find the area of contour
        if(a>largest_area){
            largest_area=a;
            largest_contour_index=i;                //Store the index of largest contour
        }
        x.push_back(contours[i][j].x);
        y.push_back(contours[i][j].y);
    }
}

drawContours( alpha,contours, largest_contour_index, Scalar(255),CV_FILLED, 8, hierarchy );
Mat rgb[3];
split(image,rgb);
    
Mat rgba[4]={rgb[0],rgb[1],rgb[2],alpha};
merge(rgba,4,transparent);
imshow("Transparent",transparent);
waitKey();
destroyAllWindows();
    

auto xVals = std::minmax_element(x.begin(), x.end());
auto yVals = std::minmax_element(y.begin(), y.end());

Rect rect (*xVals.first,*yVals.first,(*xVals.second)-(*xVals.first),(*yVals.second)-(*yVals.first));
cropped = image(rect);
return cropped;
}

The following image is the result of this code. As you can see the crop work but the image background is not transparent

enter image description here

Any help is appreciated!

Community
  • 1
  • 1
C.Radford
  • 882
  • 4
  • 13
  • 31
  • 2
    Are you saving as a filetype that has transparency? Just asking because you posted a `.jpg` and `.jpg` are only three-channel and don't support an alpha channel. – alkasm Jul 04 '17 at 18:08
  • @AlexanderReynolds thats a phenomenal point. I got this image form a screen capture though using imshow(). What filetypes do support alpha? – C.Radford Jul 04 '17 at 18:48
  • No that's okay; what you're doing is making the black pixels in the outside transparent by making their alpha channel be 0 there and nonzero elsewhere. You just need to save the result as a `.png`, it's ok if you start with a `.jpg`. Filetypes that support transparency through an alpha channel are `.png`, `.bmp`, `.tiff`, and `.jp2` (JPEG 2000) but you should probably stay away from `.jp2` if you can help it since it's compressed. – alkasm Jul 04 '17 at 18:55
  • @AlexanderReynolds thanks! Do you happen to know a way to just make the pixels null? They keep getting picked up as key points in my image which I need to avoid. – C.Radford Jul 04 '17 at 19:00
  • @AlexanderReynolds actually do you happen to know how to solve this approach? Instead of having the background as black I want to try setting it yo (0,255,0) which I can do. Do you know how I would adapt the threshold() and findContours() functions in order to find the contours I need t crop out as they would no longer be black but be green? Thanks for all your help! – C.Radford Jul 04 '17 at 19:04
  • It looks like SIFT allows you to pass in a mask like you're creating on the alpha channel. See [here](https://stackoverflow.com/questions/42346761/opencv-python-feature-detection-how-to-provide-a-mask-sift) for e.g. – alkasm Jul 04 '17 at 19:04
  • What the thresholding and contours function is providing is a way to find the border of your images. Then you draw those contours filled with white on a single-channel black image, giving your mask---white filled in your image region. You can flip the mask with `bitwise_not()` from OpenCV to get an indicator for the black region. If you wanted that region to be green, you could `merge(black_image, flipped_mask, black_image)` to create a blank image with just green in the black areas. Then you should be able to `bitwise_or()` that image with your original image to fill black areas with green. – alkasm Jul 04 '17 at 19:13
  • Or much more simply you could just loop through your image and wherever the mask is black, set the pixel to green. – alkasm Jul 04 '17 at 19:14
  • opencv doesnt handle the alpha channel during rendering or standard processing. But you can save aa png with working alpha channel. – Micka Jul 04 '17 at 19:39
  • @AlexanderReynolds if I was to set the pixels alpha to opacity of 100% would it still be considered for keypoint detection based on its bgr value? – C.Radford Jul 04 '17 at 19:39
  • 1
    No idea. Just use the alpha channel you made as a mask for SIFT. – alkasm Jul 04 '17 at 20:04
  • @AlexanderReynolds thanks for your help with this question. I was wondering if you might be willing to take a look at another question I had here: https://stackoverflow.com/questions/44914010/opencv-c-keypoints-and-descriptors-transform-with-homography-of-warped-images?noredirect=1#comment76805063_44914010 – C.Radford Jul 05 '17 at 13:16

0 Answers0