Question

I have an grayscale image, and I want to crop a rectangle of size w x h centered at pixel (x,y). The problem is, I don't want the crop to look boxy so around the edge I want to gaussian blur the values so that they smoothly transisition to zero. Any ideas on how to do this?

Currently I am doing:

int bb_min_x = center_x - width/2.0;
int bb_max_x = center_x + width/2.0;

int bb_min_y = center_y - height/2.0;
int bb_max_y = center_y + height/2.0;

for(int y = bb_min_y; y <= bb_max_y; y++){
    for(int x = bb_min_x; x <= bb_max_x; x++){
        final_img.at<uchar>(y,x) = original_img.at<uchar>(y,x);
    }
}
Was it helpful?

Solution

try this function:

compute the distance from your input rectangle and use that as a fading factor.

cv::Mat cropFade(cv::Mat _img, cv::Rect _roi, int _maxFadeDistance)
{
cv::Mat fadeMask = cv::Mat::ones(_img.size(), CV_8UC1);
cv::rectangle(fadeMask, _roi, cv::Scalar(0),-1);

cv::imshow("mask",fadeMask>0);

cv::Mat dt;
cv::distanceTransform(fadeMask > 0, dt, CV_DIST_L2 ,CV_DIST_MASK_PRECISE);



// fade to a maximum distance:
double maxFadeDist;

if(_maxFadeDistance > 0)
    maxFadeDist = _maxFadeDistance;
else
{
    // find min/max vals
    double min,max;
    cv::minMaxLoc(dt,&min,&max);
    maxFadeDist = max;
}


//dt = 1.0-(dt* 1.0/max);   // values between 0 and 1 since min val should alwaysbe 0
dt = 1.0-(dt* 1.0/maxFadeDist); // values between 0 and 1 in fading region

cv::imshow("blending mask", dt);


cv::Mat imgF;
_img.convertTo(imgF,CV_32FC3);


std::vector<cv::Mat> channels;
cv::split(imgF,channels);
// multiply pixel value with the quality weights for image 1
for(unsigned int i=0; i<channels.size(); ++i)
    channels[i] = channels[i].mul(dt);

cv::Mat outF;
cv::merge(channels,outF);

cv::Mat out;
outF.convertTo(out,CV_8UC3);



return out;
}

calling that with cv::Mat out = cropFade(in, cv::Rect(in.cols/4, in.rows/4, in.cols/2, in.rows/2), in.cols/8); gives me those results for a lena with the specified rect:

enter image description here

enter image description here

this is the result for full image fading from the same unchanged rect:

enter image description here

OTHER TIPS

One simple approach:

// Create a weight image
int border=25;
cv::Mat_<float> rect=cv::Mat_<float>::zeros(height,width)
cv::rectangle(rect,cv::Rect(border/2,border/2,width-border,height-border),cv::Scalar(1),-1);
cv::Mat_<float> weights, kernel=cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(border,border));
int nnz = cv::countNonZero(kernel);
cv::filter2D(rect,weights,-1,kernel/nnz);

This creates a weight image like the following:

enter image description here

Then you use it to fade your image out:

for(int y = bb_min_y; y <= bb_max_y; y++){
    for(int x = bb_min_x; x <= bb_max_x; x++){
        float w = weights.at<float>(y-bb_min_y,x-bb_min_x);
        uchar val = original_img.at<uchar>(y,x);
        final_img.at<uchar>(y,x) = cv::saturate_cast<uchar>(w*val);
    }
}

If you turn your bounding box into a contour you can use pointPolygonTest to calculate the distance to the edge of the bounding box for each pixel. If you then lower the color values to zero depending on this distance you get a blur effect.

See this page for an example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top