mirror of
https://github.com/opencv/opencv.git
synced 2025-07-30 17:37:05 +08:00
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:
parent
cdad0b7027
commit
60d35d1bd5
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 );
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user