OpenCV實(shí)現(xiàn)無縫克隆算法的步驟詳解
一、概述
借助無縫克隆算法,您可以從一張圖像中復(fù)制一個(gè)對(duì)象,然后將其粘貼到另一張圖像中,從而形成一個(gè)看起來無縫且自然的構(gòu)圖。
二、函數(shù)原型
給定一個(gè)原始彩色圖像,可以無縫混合該圖像的兩個(gè)不同顏色版本。
void cv::colorChange (InputArray src, InputArray mask, OutputArray dst, float red_mul=1.0f, float green_mul=1.0f, float blue_mul=1.0f)
| src | 輸入 8 位 3 通道圖像 |
| mask | 輸入 8 位 1 或 3 通道圖像 |
| dst | 輸出與 src 大小和類型相同的圖像 |
| red_mul | R 通道倍增因子 |
| green_mul | G 通道倍增因子 |
| blue_mul | B 通道倍增因子 |
對(duì)選區(qū)內(nèi)部的梯度場(chǎng)應(yīng)用適當(dāng)?shù)姆蔷€性變換,然后用泊松求解器積分,局部修改圖像的表觀照明。
void cv::illuminationChange (InputArray src, InputArray mask, OutputArray dst, float alpha=0.2f, float beta=0.4f)
| src | 輸入 8 位 3 通道圖像 |
| mask | 輸入 8 位 1 或 3 通道圖像 |
| dst | 輸出與 src 大小和類型相同的圖像 |
| alpha | 值范圍在 0-2 之間 |
| beta | 值范圍在 0-2 之間 |
圖像編輯任務(wù)涉及全局變化(顏色/強(qiáng)度校正、過濾器、變形)或與選擇有關(guān)的局部變化。 在這里,我們有興趣以無縫且輕松的方式實(shí)現(xiàn)局部更改,這些更改僅限于手動(dòng)選擇的區(qū)域 (ROI)。 變化的程度從輕微的扭曲到完全被新穎的內(nèi)容替代。
void cv::seamlessClone (InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags)
| src | 輸入 8 位 3 通道圖像 |
| dst | 輸入 8 位 3 通道圖像 |
| mask | 輸入 8 位 1 或 3 通道圖像 |
| p | 在 dst 圖像中指向放置對(duì)象的位置 |
| blend | 輸出與 dst 大小和類型相同的圖像 |
| flags | 可以是 cv::NORMAL_CLONE、cv::MIXED_CLONE 或 cv::MONOCHROME_TRANSFER 的克隆方法 |
通過僅保留邊緣位置的梯度,在與泊松求解器集成之前,可以洗掉所選區(qū)域的紋理,使其內(nèi)容具有平坦的外觀。 這里使用 Canny 邊緣檢測(cè)器。
void cv::textureFlattening (InputArray src, InputArray mask, OutputArray dst, float low_threshold=30, float high_threshold=45, int kernel_size=3)
| src | 輸入 8 位 3 通道圖像 |
| mask | 輸入 8 位 1 或 3 通道圖像 |
| dst | 輸出與 src 大小和類型相同的圖像 |
| low_threshold | 范圍從 0 到 100 |
| high_threshold | 值 > 100 |
| kernel_size | 要使用的 Sobel 內(nèi)核的大小 |
三、OpenCV源碼
1、源碼路徑
opencv\modules\photo\src\seamless_cloning.cpp
2、源碼代碼
#include "precomp.hpp"
#include "opencv2/photo.hpp"
#include "seamless_cloning.hpp"
using namespace std;
using namespace cv;
static Mat checkMask(InputArray _mask, Size size)
{
Mat mask = _mask.getMat();
Mat gray;
if (mask.channels() > 1)
cvtColor(mask, gray, COLOR_BGRA2GRAY);
else
{
if (mask.empty())
gray = Mat(size.height, size.width, CV_8UC1, Scalar(255));
else
mask.copyTo(gray);
}
return gray;
}
void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags)
{
CV_INSTRUMENT_REGION();
const Mat src = _src.getMat();
const Mat dest = _dst.getMat();
Mat mask = checkMask(_mask, src.size());
dest.copyTo(_blend);
Mat blend = _blend.getMat();
Mat mask_inner = mask(Rect(1, 1, mask.cols - 2, mask.rows - 2));
copyMakeBorder(mask_inner, mask, 1, 1, 1, 1, BORDER_ISOLATED | BORDER_CONSTANT, Scalar(0));
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();
Mat sourceROI = Mat::zeros(roi_s.height, roi_s.width, src.type());
src(roi_s).copyTo(sourceROI,mask(roi_s));
Mat maskROI = mask(roi_s);
Mat recoveredROI = blend(roi_d);
Cloning obj;
obj.normalClone(destinationROI,sourceROI,maskROI,recoveredROI,flags);
}
void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float red, float green, float blue)
{
CV_INSTRUMENT_REGION();
Mat src = _src.getMat();
Mat mask = checkMask(_mask, src.size());
_dst.create(src.size(), src.type());
Mat blend = _dst.getMat();
Mat cs_mask = Mat::zeros(src.size(), src.type());
src.copyTo(cs_mask, mask);
Cloning obj;
obj.localColorChange(src, cs_mask, mask, blend, red, green, blue);
}
void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float alpha, float beta)
{
CV_INSTRUMENT_REGION();
Mat src = _src.getMat();
Mat mask = checkMask(_mask, src.size());
_dst.create(src.size(), src.type());
Mat blend = _dst.getMat();
Mat cs_mask = Mat::zeros(src.size(), src.type());
src.copyTo(cs_mask, mask);
Cloning obj;
obj.illuminationChange(src, cs_mask, mask, blend, alpha, beta);
}
void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst,
float low_threshold, float high_threshold, int kernel_size)
{
CV_INSTRUMENT_REGION();
Mat src = _src.getMat();
Mat mask = checkMask(_mask, src.size());
_dst.create(src.size(), src.type());
Mat blend = _dst.getMat();
Mat cs_mask = Mat::zeros(src.size(), src.type());
src.copyTo(cs_mask, mask);
Cloning obj;
obj.textureFlatten(src, cs_mask, mask, low_threshold, high_threshold, kernel_size, blend);
}四、效果圖像示例



以上就是OpenCV實(shí)現(xiàn)無縫克隆算法的步驟詳解的詳細(xì)內(nèi)容,更多關(guān)于OpenCV無縫克隆算法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++ 學(xué)習(xí)筆記實(shí)戰(zhàn)寫一個(gè)簡(jiǎn)單的線程池示例
這篇文章主要為大家介紹了C++實(shí)現(xiàn)一個(gè)簡(jiǎn)單的線程池學(xué)習(xí)實(shí)戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
C++設(shè)計(jì)模式之備忘錄模式(Memento)
這篇文章主要為大家詳細(xì)介紹了C++設(shè)計(jì)模式之備忘錄模式Memento的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
C++?指針和對(duì)象成員訪問的區(qū)別:`.`?與?`->`?的使用小結(jié)
在學(xué)習(xí)?C++?時(shí),常常會(huì)遇到訪問對(duì)象成員的兩種符號(hào):.?和?->,這兩個(gè)符號(hào)看似簡(jiǎn)單,但它們的正確使用卻需要理解指針和對(duì)象的本質(zhì)差異,本文介紹C++?指針和對(duì)象成員訪問的區(qū)別:`.`?與?`->`?的使用指南,感興趣的朋友一起看看吧2024-12-12
基于Qt實(shí)現(xiàn)Android的圖案密碼效果
這篇文章主要為大家詳細(xì)介紹了如何基于Qt實(shí)現(xiàn)Android的圖案密碼效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2024-12-12
C++實(shí)現(xiàn)LeetCode(52.N皇后問題之二)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(52.N皇后問題之二),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C語(yǔ)言入門之淺談數(shù)據(jù)類型和變量常量
這篇文章主要為大家介紹了C語(yǔ)言數(shù)據(jù)類型和變量常量,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01

