Merge pull request #2608 from Siddharthk:master

pull/3028/head
Vadim Pisarevsky 10 years ago
commit 05164bf713
  1. 12
      modules/photo/doc/cloning.rst
  2. 4
      modules/photo/doc/decolor.rst
  3. 2
      modules/photo/doc/hdr_imaging.rst
  4. 8
      modules/photo/doc/npr.rst
  5. 15
      modules/photo/src/npr.hpp
  6. 2
      modules/photo/src/seamless_cloning.cpp
  7. 33
      modules/photo/src/seamless_cloning.hpp
  8. 40
      samples/cpp/tutorial_code/photo/decolorization/decolor.cpp
  9. 96
      samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp
  10. 246
      samples/cpp/tutorial_code/photo/seamless_cloning/cloning_demo.cpp
  11. 546
      samples/cpp/tutorial_code/photo/seamless_cloning/cloning_gui.cpp

@ -7,7 +7,7 @@ seamlessClone
------------- -------------
Image editing tasks concern either global changes (color/intensity corrections, filters, deformations) or local changes concerned to a selection. 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. 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. The extent of the changes ranges from slight distortions to complete replacement by novel content [PM03]_.
.. ocv:function:: void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags) .. ocv:function:: void seamlessClone( InputArray src, InputArray dst, InputArray mask, Point p, OutputArray blend, int flags)
@ -25,13 +25,9 @@ The extent of the changes ranges from slight distortions to complete replacement
* **NORMAL_CLONE** The power of the method is fully expressed when inserting objects with complex outlines into a new background * **NORMAL_CLONE** The power of the method is fully expressed when inserting objects with complex outlines into a new background
* **MIXED_CLONE** The classic method, color-based selection and alpha * **MIXED_CLONE** 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.
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.
* **FEATURE_EXCHANGE** Feature exchange allows the user to replace easily certain * **FEATURE_EXCHANGE** Feature exchange allows the user to easily replace certain features of one object by alternative features.
features of one object by alternative features.
@ -97,3 +93,5 @@ region, giving its contents a flat aspect. Here Canny Edge Detector is used.
**NOTE:** **NOTE:**
The algorithm assumes that the color of the source image is close to that of the destination. This assumption means that when the colors don't match, the source image color gets tinted toward the color of the destination image. The algorithm assumes that the color of the source image is close to that of the destination. This assumption means that when the colors don't match, the source image color gets tinted toward the color of the destination image.
.. [PM03] Patrick Perez, Michel Gangnet, Andrew Blake, "Poisson image editing", ACM Transactions on Graphics (SIGGRAPH), 2003.

@ -6,7 +6,7 @@ Decolorization
decolor decolor
------- -------
Transforms a color image to a grayscale image. It is a basic tool in digital printing, stylized black-and-white photograph rendering, and in many single channel image processing applications. Transforms a color image to a grayscale image. It is a basic tool in digital printing, stylized black-and-white photograph rendering, and in many single channel image processing applications [CL12]_.
.. ocv:function:: void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost ) .. ocv:function:: void decolor( InputArray src, OutputArray grayscale, OutputArray color_boost )
@ -17,3 +17,5 @@ Transforms a color image to a grayscale image. It is a basic tool in digital pri
:param color_boost: Output 8-bit 3-channel image. :param color_boost: Output 8-bit 3-channel image.
This function is to be applied on color images. This function is to be applied on color images.
.. [CL12] Cewu Lu, Li Xu, Jiaya Jia, "Contrast Preserving Decolorization", IEEE International Conference on Computational Photography (ICCP), 2012.

@ -356,7 +356,7 @@ Creates MergeRobertson object
.. ocv:function:: Ptr<MergeRobertson> createMergeRobertson() .. ocv:function:: Ptr<MergeRobertson> createMergeRobertson()
References References
========== ---------------------------
.. [DM03] F. Drago, K. Myszkowski, T. Annen, N. Chiba, "Adaptive Logarithmic Mapping For Displaying High Contrast Scenes", Computer Graphics Forum, 2003, 22, 419 - 426. .. [DM03] F. Drago, K. Myszkowski, T. Annen, N. Chiba, "Adaptive Logarithmic Mapping For Displaying High Contrast Scenes", Computer Graphics Forum, 2003, 22, 419 - 426.

@ -6,7 +6,7 @@ Non-Photorealistic Rendering
edgePreservingFilter edgePreservingFilter
-------------------- --------------------
Filtering is the fundamental operation in image and video processing. Edge-preserving smoothing filters are used in many different applications. Filtering is the fundamental operation in image and video processing. Edge-preserving smoothing filters are used in many different applications [EM11]_.
.. ocv:function:: void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, float sigma_s = 60, float sigma_r = 0.4f) .. ocv:function:: void edgePreservingFilter(InputArray src, OutputArray dst, int flags = 1, float sigma_s = 60, float sigma_r = 0.4f)
@ -16,9 +16,9 @@ Filtering is the fundamental operation in image and video processing. Edge-prese
:param flags: Edge preserving filters: :param flags: Edge preserving filters:
* **RECURS_FILTER** * **RECURS_FILTER** = 1
* **NORMCONV_FILTER** * **NORMCONV_FILTER** = 2
:param sigma_s: Range between 0 to 200. :param sigma_s: Range between 0 to 200.
@ -72,3 +72,5 @@ Stylization aims to produce digital imagery with a wide variety of effects not f
:param sigma_s: Range between 0 to 200. :param sigma_s: Range between 0 to 200.
:param sigma_r: Range between 0 to 1. :param sigma_r: Range between 0 to 1.
.. [EM11] Eduardo S. L. Gastal, Manuel M. Oliveira, "Domain transform for edge-aware image and video processing", ACM Trans. Graph. 30(4): 69, 2011.

@ -173,6 +173,7 @@ void Domain_Filter::compute_Rfilter(Mat &output, Mat &hz, float sigma_h)
{ {
int h = output.rows; int h = output.rows;
int w = output.cols; int w = output.cols;
int channel = output.channels();
float a = (float) exp((-1.0 * sqrt(2.0)) / sigma_h); float a = (float) exp((-1.0 * sqrt(2.0)) / sigma_h);
@ -185,11 +186,15 @@ void Domain_Filter::compute_Rfilter(Mat &output, Mat &hz, float sigma_h)
for(int j=0;j<w;j++) for(int j=0;j<w;j++)
V.at<float>(i,j) = pow(a,hz.at<float>(i,j)); V.at<float>(i,j) = pow(a,hz.at<float>(i,j));
for(int i=0; i<h; i++) for(int i=0; i<h; i++)
{ {
for(int j =1; j < w; j++) for(int j =1; j < w; j++)
{ {
temp.at<float>(i,j) = temp.at<float>(i,j) + (temp.at<float>(i,j-1) - temp.at<float>(i,j)) * V.at<float>(i,j); for(int c = 0; c<channel; c++)
{
temp.at<float>(i,j*channel+c) = temp.at<float>(i,j*channel+c) +
(temp.at<float>(i,(j-1)*channel+c) - temp.at<float>(i,j*channel+c)) * V.at<float>(i,j);
}
} }
} }
@ -197,7 +202,11 @@ void Domain_Filter::compute_Rfilter(Mat &output, Mat &hz, float sigma_h)
{ {
for(int j =w-2; j >= 0; j--) for(int j =w-2; j >= 0; j--)
{ {
temp.at<float>(i,j) = temp.at<float>(i,j) + (temp.at<float>(i,j+1) - temp.at<float>(i,j)) * V.at<float>(i,j+1); for(int c = 0; c<channel; c++)
{
temp.at<float>(i,j*channel+c) = temp.at<float>(i,j*channel+c) +
(temp.at<float>(i,(j+1)*channel+c) - temp.at<float>(i,j*channel+c))*V.at<float>(i,j+1);
}
} }
} }

@ -108,6 +108,7 @@ void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point
Cloning obj; Cloning obj;
obj.normal_clone(dest,cd_mask,dst_mask,blend,flags); obj.normal_clone(dest,cd_mask,dst_mask,blend,flags);
} }
void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b) void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b)
@ -136,7 +137,6 @@ void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float
obj.local_color_change(src,cs_mask,gray,blend,red,green,blue); obj.local_color_change(src,cs_mask,gray,blend,red,green,blue);
} }
void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b) void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b)
{ {

@ -455,6 +455,8 @@ void Cloning::normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num)
{ {
int w = I.size().width; int w = I.size().width;
int h = I.size().height; int h = I.size().height;
int channel = I.channels();
initialization(I,mask,wmask); initialization(I,mask,wmask);
@ -466,20 +468,33 @@ void Cloning::normal_clone(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, int num)
} }
else if(num == 2) else if(num == 2)
{ {
for(int i=0;i < h; i++) for(int i=0;i < h; i++)
for(int j=0; j < w; j++) {
for(int j=0; j < w; j++)
{ {
if(abs(sgx.at<float>(i,j) - sgy.at<float>(i,j)) > abs(grx.at<float>(i,j) - gry.at<float>(i,j))) for(int c=0;c<channel;++c)
{ {
srx32.at<float>(i,j) = sgx.at<float>(i,j) * smask.at<float>(i,j); if(abs(sgx.at<float>(i,j*channel+c) - sgy.at<float>(i,j*channel+c)) >
sry32.at<float>(i,j) = sgy.at<float>(i,j) * smask.at<float>(i,j); abs(grx.at<float>(i,j*channel+c) - gry.at<float>(i,j*channel+c)))
} {
else
{ srx32.at<float>(i,j*channel+c) = sgx.at<float>(i,j*channel+c)
srx32.at<float>(i,j) = grx.at<float>(i,j) * smask.at<float>(i,j); * smask.at<float>(i,j);
sry32.at<float>(i,j) = gry.at<float>(i,j) * smask.at<float>(i,j); sry32.at<float>(i,j*channel+c) = sgy.at<float>(i,j*channel+c)
* smask.at<float>(i,j);
}
else
{
srx32.at<float>(i,j*channel+c) = grx.at<float>(i,j*channel+c)
* smask.at<float>(i,j);
sry32.at<float>(i,j*channel+c) = gry.at<float>(i,j*channel+c)
* smask.at<float>(i,j);
}
} }
} }
}
} }
else if(num == 3) else if(num == 3)
{ {

@ -0,0 +1,40 @@
/*
* decolor.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV Decolorization Module.
*
* Input:
* Color Image
*
* Output:
* 1) Grayscale image
* 2) Color boost image
*
*/
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
using namespace std;
using namespace cv;
int main(int argc, char *argv[])
{
CV_Assert(argc == 2);
Mat I;
I = imread(argv[1]);
Mat gray = Mat(I.size(),CV_8UC1);
Mat color_boost = Mat(I.size(),CV_8UC3);
decolor(I,gray,color_boost);
imshow("grayscale",gray);
imshow("color_boost",color_boost);
waitKey(0);
}

@ -0,0 +1,96 @@
/*
* npr_demo.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV Non-Photorealistic Rendering Module.
* 1) Edge Preserve Smoothing
* -> Using Normalized convolution Filter
* -> Using Recursive Filter
* 2) Detail Enhancement
* 3) Pencil sketch/Color Pencil Drawing
* 4) Stylization
*
*/
#include <signal.h>
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main(int argc, char* argv[])
{
if(argc < 2)
{
cout << "usage: " << argv[0] << " <Input image> " << endl;
exit(0);
}
int num,type;
Mat I = imread(argv[1]);
if(!I.data)
{
cout << "Image not found" << endl;
exit(0);
}
cout << endl;
cout << " Edge Preserve Filter" << endl;
cout << "----------------------" << endl;
cout << "Options: " << endl;
cout << endl;
cout << "1) Edge Preserve Smoothing" << endl;
cout << " -> Using Normalized convolution Filter" << endl;
cout << " -> Using Recursive Filter" << endl;
cout << "2) Detail Enhancement" << endl;
cout << "3) Pencil sketch/Color Pencil Drawing" << endl;
cout << "4) Stylization" << endl;
cout << endl;
cout << "Press number 1-4 to choose from above techniques: ";
cin >> num;
Mat img;
if(num == 1)
{
cout << endl;
cout << "Press 1 for Normalized Convolution Filter and 2 for Recursive Filter: ";
cin >> type;
edgePreservingFilter(I,img,type);
imshow("Edge Preserve Smoothing",img);
}
else if(num == 2)
{
detailEnhance(I,img);
imshow("Detail Enhanced",img);
}
else if(num == 3)
{
Mat img1;
pencilSketch(I,img1, img, 10 , 0.1f, 0.03f);
imshow("Pencil Sketch",img1);
imshow("Color Pencil Sketch",img);
}
else if(num == 4)
{
stylization(I,img);
imshow("Stylization",img);
}
waitKey(0);
}

@ -0,0 +1,246 @@
/*
* cloning_demo.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV seamless cloning
* module without GUI.
*
* 1- Normal Cloning
* 2- Mixed Cloning
* 3- Monochrome Transfer
* 4- Color Change
* 5- Illumination change
* 6- Texture Flattening
* The program takes as input a source and a destination image (for 1-3 methods)
* and ouputs the cloned image.
*
* Download test images from opencv_extra folder @github.
*
*/
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
#include <stdlib.h>
using namespace std;
using namespace cv;
int main()
{
cout << endl;
cout << "Cloning Module" << endl;
cout << "---------------" << endl;
cout << "Options: " << endl;
cout << endl;
cout << "1) Normal Cloning " << endl;
cout << "2) Mixed Cloning " << endl;
cout << "3) Monochrome Transfer " << endl;
cout << "4) Local Color Change " << endl;
cout << "5) Local Illumination Change " << endl;
cout << "6) Texture Flattening " << endl;
cout << endl;
cout << "Press number 1-6 to choose from above techniques: ";
int num = 1;
cin >> num;
cout << endl;
if(num == 1)
{
string folder = "cloning/Normal_Cloning/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "destination1.png";
string original_path3 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat destination = imread(original_path2, IMREAD_COLOR);
Mat mask = imread(original_path3, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(destination.empty())
{
cout << "Could not load destination image " << original_path2 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path3 << endl;
exit(0);
}
Mat result;
Point p;
p.x = 400;
p.y = 100;
seamlessClone(source, destination, mask, p, result, 1);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
else if(num == 2)
{
string folder = "cloning/Mixed_Cloning/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "destination1.png";
string original_path3 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat destination = imread(original_path2, IMREAD_COLOR);
Mat mask = imread(original_path3, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(destination.empty())
{
cout << "Could not load destination image " << original_path2 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path3 << endl;
exit(0);
}
Mat result;
Point p;
p.x = destination.size().width/2;
p.y = destination.size().height/2;
seamlessClone(source, destination, mask, p, result, 2);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
else if(num == 3)
{
string folder = "cloning/Monochrome_Transfer/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "destination1.png";
string original_path3 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat destination = imread(original_path2, IMREAD_COLOR);
Mat mask = imread(original_path3, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(destination.empty())
{
cout << "Could not load destination image " << original_path2 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path3 << endl;
exit(0);
}
Mat result;
Point p;
p.x = destination.size().width/2;
p.y = destination.size().height/2;
seamlessClone(source, destination, mask, p, result, 3);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
else if(num == 4)
{
string folder = "cloning/Color_Change/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat mask = imread(original_path2, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path2 << endl;
exit(0);
}
Mat result;
colorChange(source, mask, result, 1.5, .5, .5);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
else if(num == 5)
{
string folder = "cloning/Illumination_Change/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat mask = imread(original_path2, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path2 << endl;
exit(0);
}
Mat result;
illuminationChange(source, mask, result, 0.2f, 0.4f);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
else if(num == 6)
{
string folder = "cloning/Texture_Flattening/";
string original_path1 = folder + "source1.png";
string original_path2 = folder + "mask.png";
Mat source = imread(original_path1, IMREAD_COLOR);
Mat mask = imread(original_path2, IMREAD_COLOR);
if(source.empty())
{
cout << "Could not load source image " << original_path1 << endl;
exit(0);
}
if(mask.empty())
{
cout << "Could not load mask image " << original_path2 << endl;
exit(0);
}
Mat result;
textureFlattening(source, mask, result, 30, 45, 3);
imshow("Output",result);
imwrite(folder + "cloned.png", result);
}
waitKey(0);
}

@ -0,0 +1,546 @@
/*
* cloning.cpp
*
* Author:
* Siddharth Kherada <siddharthkherada27[at]gmail[dot]com>
*
* This tutorial demonstrates how to use OpenCV seamless cloning
* module.
*
* 1- Normal Cloning
* 2- Mixed Cloning
* 3- Monochrome Transfer
* 4- Color Change
* 5- Illumination change
* 6- Texture Flattening
* The program takes as input a source and a destination image (for 1-3 methods)
* and ouputs the cloned image.
* Step 1:
* -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button.
* -> To set the Polygon ROI, click the right mouse button or 'd' key.
* -> To reset the region selected, click the middle mouse button or 'r' key.
* Step 2:
* -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button.
* -> To get the cloned result, click the right mouse button or 'c' key.
* -> To quit the program, use 'q' key.
*
* Result: The cloned image will be displayed.
*/
#include <signal.h>
#include "opencv2/photo.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include <iostream>
#include <stdlib.h>
using namespace std;
using namespace cv;
Mat img0, img1, img2, res, res1, final, final1, blend;
Point point;
int drag = 0;
int destx, desty;
int numpts = 100;
Point* pts = new Point[100];
Point* pts2 = new Point[100];
Point* pts_diff = new Point[100];
int var = 0;
int flag = 0, flag1 = 0, flag4 = 0;
int minx, miny, maxx, maxy, lenx, leny;
int minxd, minyd, maxxd, maxyd, lenxd, lenyd;
int channel, num, kernel_size;
float alpha,beta;
float red, green, blue;
double low_t, high_t;
void source(int, int, int, int, void*);
void destination(int, int, int, int, void*);
void checkfile(char*);
void source(int event, int x, int y, int, void*)
{
if (event == EVENT_LBUTTONDOWN && !drag)
{
if(flag1 == 0)
{
if(var==0)
img1 = img0.clone();
point = Point(x, y);
circle(img1,point,2,Scalar(0, 0, 255),-1, 8, 0);
pts[var] = point;
var++;
drag = 1;
if(var>1)
line(img1,pts[var-2], point, Scalar(0, 0, 255), 2, 8, 0);
imshow("Source", img1);
}
}
if (event == EVENT_LBUTTONUP && drag)
{
imshow("Source", img1);
drag = 0;
}
if (event == EVENT_RBUTTONDOWN)
{
flag1 = 1;
img1 = img0.clone();
for(int i = var; i < numpts ; i++)
pts[i] = point;
if(var!=0)
{
const Point* pts3[1] = {&pts[0]};
polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
}
for(int i=0;i<var;i++)
{
minx = min(minx,pts[i].x);
maxx = max(maxx,pts[i].x);
miny = min(miny,pts[i].y);
maxy = max(maxy,pts[i].y);
}
lenx = maxx - minx;
leny = maxy - miny;
int mid_pointx = minx + lenx/2;
int mid_pointy = miny + leny/2;
for(int i=0;i<var;i++)
{
pts_diff[i].x = pts[i].x - mid_pointx;
pts_diff[i].y = pts[i].y - mid_pointy;
}
imshow("Source", img1);
}
if (event == EVENT_RBUTTONUP)
{
flag = var;
final = Mat::zeros(img0.size(),CV_8UC3);
res1 = Mat::zeros(img0.size(),CV_8UC1);
const Point* pts4[1] = {&pts[0]};
fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
bitwise_and(img0, img0, final,res1);
imshow("Source", img1);
if(num == 4)
{
colorChange(img0,res1,blend,red,green,blue);
imshow("Color Change Image", blend);
waitKey(0);
}
else if(num == 5)
{
illuminationChange(img0,res1,blend,alpha,beta);
imshow("Illum Change Image", blend);
waitKey(0);
}
else if(num == 6)
{
textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
imshow("Texture Flattened", blend);
waitKey(0);
}
}
if (event == EVENT_MBUTTONDOWN)
{
for(int i = 0; i < numpts ; i++)
{
pts[i].x=0;
pts[i].y=0;
}
var = 0;
flag1 = 0;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
imshow("Source", img0);
if(num == 1 || num == 2 || num == 3)
imshow("Destination",img2);
drag = 0;
}
}
void destination(int event, int x, int y, int, void*)
{
Mat im1;
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
im1 = img2.clone();
if (event == EVENT_LBUTTONDOWN)
{
flag4 = 1;
if(flag1 == 1)
{
point = Point(x, y);
for(int i=0;i<var;i++)
{
pts2[i].x = point.x + pts_diff[i].x;
pts2[i].y = point.y + pts_diff[i].y;
}
for(int i=var;i<numpts;i++)
{
pts2[i].x = point.x + pts_diff[0].x;
pts2[i].y = point.y + pts_diff[0].y;
}
const Point* pts5[1] = {&pts2[0]};
polylines( im1, pts5, &numpts,1, 1, Scalar(0,0,255), 2, 8, 0);
destx = x;
desty = y;
imshow("Destination", im1);
}
}
if (event == EVENT_RBUTTONUP)
{
for(int i=0;i<flag;i++)
{
minxd = min(minxd,pts2[i].x);
maxxd = max(maxxd,pts2[i].x);
minyd = min(minyd,pts2[i].y);
maxyd = max(maxyd,pts2[i].y);
}
if(maxxd > im1.size().width || maxyd > im1.size().height || minxd < 0 || minyd < 0)
{
cout << "Index out of range" << endl;
exit(0);
}
final1 = Mat::zeros(img2.size(),CV_8UC3);
res = Mat::zeros(img2.size(),CV_8UC1);
for(int i=miny, k=minyd;i<(miny+leny);i++,k++)
for(int j=minx,l=minxd ;j<(minx+lenx);j++,l++)
{
for(int c=0;c<channel;c++)
{
final1.at<uchar>(k,l*channel+c) = final.at<uchar>(i,j*channel+c);
}
}
const Point* pts6[1] = {&pts2[0]};
fillPoly(res, pts6, &numpts, 1, Scalar(255, 255, 255), 8, 0);
if(num == 1 || num == 2 || num == 3)
{
seamlessClone(img0,img2,res1,point,blend,num);
imshow("Cloned Image", blend);
imwrite("cloned.png",blend);
waitKey(0);
}
for(int i = 0; i < flag ; i++)
{
pts2[i].x=0;
pts2[i].y=0;
}
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
}
im1.release();
}
int main()
{
cout << endl;
cout << "Cloning Module" << endl;
cout << "---------------" << endl;
cout << "Step 1:" << endl;
cout << " -> In the source image, select the region of interest by left click mouse button. A Polygon ROI will be created by left clicking mouse button." << endl;
cout << " -> To set the Polygon ROI, click the right mouse button or use 'd' key" << endl;
cout << " -> To reset the region selected, click the middle mouse button or use 'r' key." << endl;
cout << "Step 2:" << endl;
cout << " -> In the destination image, select the point where you want to place the ROI in the image by left clicking mouse button." << endl;
cout << " -> To get the cloned result, click the right mouse button or use 'c' key." << endl;
cout << " -> To quit the program, use 'q' key." << endl;
cout << endl;
cout << "Options: " << endl;
cout << endl;
cout << "1) Normal Cloning " << endl;
cout << "2) Mixed Cloning " << endl;
cout << "3) Monochrome Transfer " << endl;
cout << "4) Local Color Change " << endl;
cout << "5) Local Illumination Change " << endl;
cout << "6) Texture Flattening " << endl;
cout << endl;
cout << "Press number 1-6 to choose from above techniques: ";
cin >> num;
cout << endl;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
minxd = INT_MAX; minyd = INT_MAX; maxxd = INT_MIN; maxyd = INT_MIN;
int flag3 = 0;
if(num == 1 || num == 2 || num == 3)
{
string src,dest;
cout << "Enter Source Image: ";
cin >> src;
cout << "Enter Destination Image: ";
cin >> dest;
img0 = imread(src);
img2 = imread(dest);
if(!img0.data)
{
cout << "Source Image does not exist" << endl;
exit(0);
}
if(!img2.data)
{
cout << "Destination Image does not exist" << endl;
exit(0);
}
channel = img0.channels();
res = Mat::zeros(img2.size(),CV_8UC1);
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
final1 = Mat::zeros(img2.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
/////////// destination image ///////////////
namedWindow("Destination", 1);
setMouseCallback("Destination", destination, NULL);
imshow("Destination",img2);
}
else if(num == 4)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "Enter RGB values: " << endl;
cout << "Red: ";
cin >> red;
cout << "Green: ";
cin >> green;
cout << "Blue: ";
cin >> blue;
img0 = imread(src);
if(!img0.data)
{
cout << "Source Image does not exist" << endl;
exit(0);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else if(num == 5)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "alpha: ";
cin >> alpha;
cout << "beta: ";
cin >> beta;
img0 = imread(src);
if(!img0.data)
{
cout << "Source Image does not exist" << endl;
exit(0);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else if(num == 6)
{
string src;
cout << "Enter Source Image: ";
cin >> src;
cout << "low_threshold: ";
cin >> low_t;
cout << "high_threshold: ";
cin >> high_t;
cout << "kernel_size: ";
cin >> kernel_size;
img0 = imread(src);
if(!img0.data)
{
cout << "Source Image does not exist" << endl;
exit(0);
}
res1 = Mat::zeros(img0.size(),CV_8UC1);
final = Mat::zeros(img0.size(),CV_8UC3);
//////////// source image ///////////////////
namedWindow("Source", 1);
setMouseCallback("Source", source, NULL);
imshow("Source", img0);
}
else
{
cout << "Wrong Option Choosen" << endl;
exit(0);
}
for(;;)
{
char key = (char) waitKey(0);
if(key == 'd' && flag3 == 0)
{
flag1 = 1;
flag3 = 1;
img1 = img0.clone();
for(int i = var; i < numpts ; i++)
pts[i] = point;
if(var!=0)
{
const Point* pts3[1] = {&pts[0]};
polylines( img1, pts3, &numpts,1, 1, Scalar(0,0,0), 2, 8, 0);
}
for(int i=0;i<var;i++)
{
minx = min(minx,pts[i].x);
maxx = max(maxx,pts[i].x);
miny = min(miny,pts[i].y);
maxy = max(maxy,pts[i].y);
}
lenx = maxx - minx;
leny = maxy - miny;
int mid_pointx = minx + lenx/2;
int mid_pointy = miny + leny/2;
for(int i=0;i<var;i++)
{
pts_diff[i].x = pts[i].x - mid_pointx;
pts_diff[i].y = pts[i].y - mid_pointy;
}
flag = var;
final = Mat::zeros(img0.size(),CV_8UC3);
res1 = Mat::zeros(img0.size(),CV_8UC1);
const Point* pts4[1] = {&pts[0]};
fillPoly(res1, pts4,&numpts, 1, Scalar(255, 255, 255), 8, 0);
bitwise_and(img0, img0, final,res1);
imshow("Source", img1);
}
else if(key == 'r')
{
for(int i = 0; i < numpts ; i++)
{
pts[i].x=0;
pts[i].y=0;
}
var = 0;
flag1 = 0;
flag3 = 0;
flag4 = 0;
minx = INT_MAX; miny = INT_MAX; maxx = INT_MIN; maxy = INT_MIN;
imshow("Source", img0);
if(num == 1 || num == 2 || num == 3)
imshow("Destination",img2);
drag = 0;
}
else if ((num == 1 || num == 2 || num == 3) && key == 'c' && flag1 == 1 && flag4 == 1)
{
seamlessClone(img0,img2,res1,point,blend,num);
imshow("Cloned Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 4 && key == 'c' && flag1 == 1)
{
colorChange(img0,res1,blend,red,green,blue);
imshow("Color Change Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 5 && key == 'c' && flag1 == 1)
{
illuminationChange(img0,res1,blend,alpha,beta);
imshow("Illum Change Image", blend);
imwrite("cloned.png",blend);
}
else if (num == 6 && key == 'c' && flag1 == 1)
{
textureFlattening(img0,res1,blend,low_t,high_t,kernel_size);
imshow("Texture Flattened", blend);
imwrite("cloned.png",blend);
}
else if(key == 'q')
exit(0);
}
waitKey(0);
}
Loading…
Cancel
Save