Merge pull request #26511 from sturkmen72:proposed_fix_for_21902

* add alternative flags to cv::seamlessClone

* Update photo.hpp

* Update seamless_cloning.cpp

* Update seamless_cloning_impl.cpp
This commit is contained in:
Suleyman TURKMEN 2024-12-19 11:57:58 +03:00 committed by GitHub
parent cdad0b7027
commit 60d35d1bd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 82 additions and 29 deletions

View File

@ -708,33 +708,74 @@ CV_EXPORTS_W void decolor( InputArray src, OutputArray grayscale, OutputArray co
//! @{
//! seamlessClone algorithm flags
enum
//! Flags for the seamlessClone algorithm
enum SeamlessCloneFlags
{
/** The power of the method is fully expressed when inserting objects with complex outlines into a new background*/
/**
@brief Normal seamless cloning.
This method is ideal for inserting objects with complex outlines into a new background.
It preserves the original appearance and lighting of the inserted object, ensuring a natural blend.
*/
NORMAL_CLONE = 1,
/** The classic method, color-based selection and alpha masking might be time consuming and often leaves an undesirable
halo. Seamless cloning, even averaged with the original image, is not effective. Mixed seamless cloning based on a loose selection proves effective.*/
MIXED_CLONE = 2,
/** Monochrome transfer allows the user to easily replace certain features of one object by alternative features.*/
MONOCHROME_TRANSFER = 3};
/**
@brief Mixed seamless cloning.
This method addresses cases where simple color-based selection or alpha masking is time-consuming
and may result in undesirable halos. By combining structure from the source and texture from the
destination, mixed seamless cloning is highly effective, even with loosely defined selections.
*/
MIXED_CLONE = 2,
/**
@brief Monochrome transfer cloning.
This method allows users to replace specific features of an object, such as grayscale textures
or patterns, with alternative features. It is particularly useful for artistic effects or
targeted object modifications.
*/
MONOCHROME_TRANSFER = 3,
/**
@brief Enhanced normal seamless cloning.
Similar to `NORMAL_CLONE`, but with an advanced approach to ROI (Region of Interest) calculation.
This mode processes a larger source region by considering the entire mask area instead of only
the bounding rectangle of non-zero pixels.
*/
NORMAL_CLONE_WIDE = 9,
/**
@brief Enhanced mixed seamless cloning.
Similar to `MIXED_CLONE`, but with an advanced approach to ROI (Region of Interest) calculation.
This mode processes a larger source region by considering the entire mask area instead of only
the bounding rectangle of non-zero pixels.
*/
MIXED_CLONE_WIDE = 10,
/**
@brief Enhanced monochrome transfer cloning.
Similar to `MONOCHROME_TRANSFER`, but with an advanced approach to ROI (Region of Interest) calculation.
This mode processes a larger source region by considering the entire mask area instead of only
the bounding rectangle of non-zero pixels.
*/
MONOCHROME_TRANSFER_WIDE = 11
};
/** @example samples/cpp/tutorial_code/photo/seamless_cloning/cloning_demo.cpp
An example using seamlessClone function
*/
/** @brief Image editing tasks concern either global changes (color/intensity corrections, filters,
deformations) or local changes concerned to a selection. Here we are interested in achieving local
changes, ones that are restricted to a region manually selected (ROI), in a seamless and effortless
manner. The extent of the changes ranges from slight distortions to complete replacement by novel
content @cite PM03 .
/** @brief Performs seamless cloning to blend a region from a source image into a destination image.
This function is designed for local image editing, allowing changes restricted to a region
(manually selected as the ROI) to be applied effortlessly and seamlessly. These changes can
range from slight distortions to complete replacement by novel content @cite PM03.
@param src Input 8-bit 3-channel image.
@param dst Input 8-bit 3-channel image.
@param mask Input 8-bit 1 or 3-channel image.
@param p Point in dst image where object is placed.
@param blend Output image with the same size and type as dst.
@param flags Cloning method that could be cv::NORMAL_CLONE, cv::MIXED_CLONE or cv::MONOCHROME_TRANSFER
@param src The source image (8-bit 3-channel), from which a region will be blended into the destination.
@param dst The destination image (8-bit 3-channel), where the src image will be blended.
@param mask A binary mask (8-bit, 1, 3, or 4-channel) specifying the region in the source image to blend.
Non-zero pixels indicate the region to be blended. If an empty Mat is provided, a mask with
all non-zero pixels is created internally.
@param p The point where the center of the src image is placed in the dst image.
@param blend The output image that stores the result of the seamless cloning. It has the same size and type as `dst`.
@param flags Flags that control the type of cloning method, can take values of `cv::SeamlessCloneFlags`.
*/
CV_EXPORTS_W void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p,
OutputArray blend, int flags);

View File

@ -47,18 +47,17 @@
using namespace std;
using namespace cv;
static Mat checkMask(InputArray _mask, Size size)
static Mat checkMask(InputArray mask, Size size)
{
Mat mask = _mask.getMat();
Mat gray;
if (mask.channels() > 1)
if (mask.channels() == 3 || mask.channels() == 4)
cvtColor(mask, gray, COLOR_BGRA2GRAY);
else
{
if (mask.empty())
gray = Mat(size.height, size.width, CV_8UC1, Scalar(255));
else
mask.copyTo(gray);
return mask.getMat();
}
return gray;
@ -68,9 +67,11 @@ void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_Assert(!_dst.empty());
const Mat src = _src.getMat();
const Mat dest = _dst.getMat();
Mat mask = checkMask(_mask, src.size());
dest.copyTo(_blend);
Mat blend = _blend.getMat();
@ -80,10 +81,18 @@ void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point
Rect roi_s = boundingRect(mask);
if (roi_s.empty()) return;
Rect roi_d(p.x - roi_s.width / 2, p.y - roi_s.height / 2, roi_s.width, roi_s.height);
Mat destinationROI = dest(roi_d).clone();
int l_from_center = p.x - roi_s.width / 2;
int t_from_center = p.y - roi_s.height / 2;
if (flags >= NORMAL_CLONE_WIDE)
{
l_from_center = p.x - (mask.cols / 2 - roi_s.x);
t_from_center = p.y - (mask.rows / 2 - roi_s.y);
}
Rect roi_d(l_from_center, t_from_center, roi_s.width, roi_s.height);
Mat destinationROI = dest(roi_d);
Mat sourceROI = Mat::zeros(roi_s.height, roi_s.width, src.type());
src(roi_s).copyTo(sourceROI,mask(roi_s));

View File

@ -332,11 +332,13 @@ void Cloning::normalClone(const Mat &destination, const Mat &patch, Mat &binaryM
switch(flag)
{
case NORMAL_CLONE:
case NORMAL_CLONE_WIDE:
arrayProduct(patchGradientX, binaryMaskFloat, patchGradientX);
arrayProduct(patchGradientY, binaryMaskFloat, patchGradientY);
break;
case MIXED_CLONE:
case MIXED_CLONE_WIDE:
{
AutoBuffer<int> maskIndices(n_elem_in_line);
for (int i = 0; i < n_elem_in_line; ++i)
@ -373,6 +375,7 @@ void Cloning::normalClone(const Mat &destination, const Mat &patch, Mat &binaryM
break;
case MONOCHROME_TRANSFER:
case MONOCHROME_TRANSFER_WIDE:
Mat gray;
cvtColor(patch, gray, COLOR_BGR2GRAY );

View File

@ -75,7 +75,7 @@ TEST(Photo_SeamlessClone_normal, regression)
Point p;
p.x = destination.size().width/2;
p.y = destination.size().height/2;
seamlessClone(source, destination, mask, p, result, 1);
seamlessClone(source, destination, mask, p, result, NORMAL_CLONE);
Mat reference = imread(reference_path);
ASSERT_FALSE(reference.empty()) << "Could not load reference image " << reference_path;
@ -88,7 +88,7 @@ TEST(Photo_SeamlessClone_normal, regression)
EXPECT_LE(errorL1, reference.total() * numerical_precision) << "size=" << reference.size();
mask = Scalar(0, 0, 0);
seamlessClone(source, destination, mask, p, result, 1);
seamlessClone(source, destination, mask, p, result, NORMAL_CLONE);
reference = destination;
errorINF = cvtest::norm(reference, result, NORM_INF);
@ -117,7 +117,7 @@ TEST(Photo_SeamlessClone_mixed, regression)
Point p;
p.x = destination.size().width/2;
p.y = destination.size().height/2;
seamlessClone(source, destination, mask, p, result, 2);
seamlessClone(source, destination, mask, p, result, MIXED_CLONE);
SAVE(result);
@ -150,7 +150,7 @@ TEST(Photo_SeamlessClone_featureExchange, regression)
Point p;
p.x = destination.size().width/2;
p.y = destination.size().height/2;
seamlessClone(source, destination, mask, p, result, 3);
seamlessClone(source, destination, mask, p, result, MONOCHROME_TRANSFER);
SAVE(result);