起因:身处大学身不由己,总有些社团活动需要拉外联啥的,一拉外联就的朋友圈发广告,还不能发私密。为了一劳永逸的解决这个问题,自己用pyhton写了一个类似于p图的代码。
目的:将一张朋友圈截图中的某一矩形区域替换为另一图片中的矩形区域。
原理:利用opencv给图片加上滑动条以及实现截取区域。
使用方法:在source窗口截取矩形区域,在material窗口点击会自动勾出等大矩形区域,按空格保存图片。
不足:滑动条部分,两张图片是共享的,现在懒得改了。。。。
代码:
#include
#include
using namespace cv;
using namespace std;
int h_x = 0, v_y = 0, d_x = 0, d_y = 0; //记录滑动条变化值,以及保存当前值
Rect v_bar, h_bar;
bool x_change = false;
bool y_change = false; //判断是否改变
bool drawbox = false;
int width, height;
Rect source_rect, _rectangle, product_rect;
int img_x=0, img_y=0; //记录滑动后截取图片在原图片中的位置
Rect roi_sour, roi_mater; //进行p图的部分
void on_mouse(int event, int x, int y, int flags, void* param);
void draw_scrolls(Mat src_img,Mat& tempimg, const char* title, int width = 1400, int height = 700);
void DrawRect(Mat& img, Rect box);
void on_mouse_2(int event, int x, int y, int flags, void* param);
void ROI_linearBlending(Mat srcImg_1, Mat srcImg_2);
int main()
{
const char* title = "source";
const char* title2 = "material";
Mat srcimg = imread("E:\\material\\pyq1.png");
Mat srcimg2 = imread("E:\\material\\pyq2.png");
Mat dstimg1,dstimg2;
Mat tempimg1,tempimg2;
namedWindow(title, 1);
namedWindow(title2, 1);
setMouseCallback(title, on_mouse);
setMouseCallback(title2, on_mouse_2);
while (true)
{
char c = waitKey(10);
draw_scrolls(srcimg, dstimg1,title);
draw_scrolls(srcimg2, dstimg2, title2);
dstimg1.copyTo(tempimg1);
dstimg2.copyTo(tempimg2);
if (drawbox)
{
DrawRect(tempimg1, _rectangle);//绘制标识符为真时,画矩形
roi_sour=(Rect(_rectangle.x + img_x, _rectangle.y + img_y, _rectangle.width, _rectangle.height));
}
DrawRect(tempimg2, product_rect);
roi_mater = (Rect(product_rect.x+img_x, product_rect.y+img_y, product_rect.width, product_rect.height));
if (c == ' ')
break;
imshow(title, tempimg1);
imshow(title2, tempimg2);
}
ROI_linearBlending(srcimg, srcimg2);
waitKey(0);
}
//图片加滑动条
void draw_scrolls(Mat src_img, Mat& temp_img,const char* title, int width, int height)
{
Mat src_rect, temp_rect;
Mat src_roi;
Rect v_rect, h_rect;
int img_width, img_height; //img的width和height
int win_width, win_height; //window的width和height
int show_width, show_height; //窗口中图片的width和height
int bar_width = 25; //滑动条的宽度
double scale_h, scale_w; //img和window的width,height之比
img_width = src_img.cols;
img_height = src_img.rows;
win_width = show_width = min(img_width, width);
win_height = show_height = min(img_height, height);
scale_h = (double)img_height / height;
scale_w = (double)img_width / width;
//高度过高需要加竖直滑动
if (scale_h > 1)
{
win_width = img_width > width ? width + bar_width : img_width + bar_width;
show_width = win_width - bar_width;
}
//宽度过宽需要加水平滑动
if (scale_w > 1)
{
win_height = img_height > height ? height + bar_width : img_height + bar_width;
show_height = win_height - bar_width;
}
temp_img = Mat::zeros(Size(win_width, win_height), CV_8UC3);
if (scale_h > 1)
{
v_y += d_y;
d_y = 0;
v_y = v_y < 0 ? 0 : (v_y > (int)((1 - 1 / scale_h) * win_height) ? (int)((1 - 1 / scale_h) * win_height) : v_y);
img_y = (int)(v_y * img_height / win_height);//img_y = (int)(v_y / ((1-1/scale_h) * win_height) * (1 - 1 / scale_h)*img_height)的简化
v_rect = Rect(show_width + 1, 0, bar_width, win_height); //竖直滑动条底层
v_bar = Rect(show_width + 1, v_y, bar_width, (int)((double)win_height / scale_h)); //竖直滑动条
rectangle(temp_img, v_rect, Scalar::all(0), -1);
rectangle(temp_img, v_bar, Scalar::all(255), -1);
}
if (scale_w > 1)
{
h_x += d_x;
d_x = 0;
h_x = h_x < 0 ? 0 : (h_x > (int)((1 - 1 / scale_w) * win_width) ? (int)((1 - 1 / scale_w) * win_width) : h_x);
img_x = (int)(h_x * img_width / win_width);//img_y = (int)(v_y / ((1-1/scale_h) * win_height) * (1 - 1 / scale_h)*img_height)的简化
h_rect = Rect(0, show_height + 1, win_width, bar_width); //水平滑动条底层
h_bar = Rect(img_x, show_height + 1, (int)((double)win_width / scale_w), bar_width); //水平滑动条
rectangle(temp_img, h_rect, Scalar::all(0), -1);
rectangle(temp_img, h_bar, Scalar::all(255), -1);
}
temp_rect = temp_img(Rect(0, 0, show_width, show_height)); //窗口显示图片部分
src_rect = src_img(Rect(img_x, img_y, show_width, show_height)); //原图截取部分
src_rect.copyTo(temp_rect);
}
//在第一张图上截取的部分
void on_mouse(int event, int x, int y, int flags, void* param)
{
Point curse = Point(x, y);
Point end, now;
static Point start = Point(-1, -1); //定义静态变量
//点击滑动条
if (event == EVENT_LBUTTONDOWN)
{
start = Point(x, y);
if (v_bar.contains(curse))
y_change = true;
else if (h_bar.contains(curse))
x_change = true;
else
{
cout < 0 ? end.x - start.x : start.x - end.x;
height = end.y - start.y > 0 ? end.y - start.y : start.y - end.y;
source_rect = Rect(start, end);
//DrawRect(tempimg1,source_rect);
drawbox = false;
}
_rectangle = Rect(start, now);
}
//第二章图上截取
void on_mouse_2(int event, int x, int y, int flags, void* param)
{
Point curse = Point(x, y);
Point end, now;
static Point start = Point(-1, -1);
bool l_drawbox = false;
//点击滑动条
if (event == EVENT_LBUTTONDOWN)
{
start = Point(x, y);
if (v_bar.contains(curse))
y_change = true;
else if (h_bar.contains(curse))
x_change = true;
else
{
cout << "(" << x << "," << y << ")";
product_rect = Rect(x, y, width, height);
l_drawbox = true;
}
}
//拖动
if (event == EVENT_MOUSEMOVE)
{
if (y_change)
{
now = Point(x, y);
d_y = now.y - start.y;
start = now;
}
if (x_change)
{
now = Point(x, y);
d_x = now.x - start.x;
start = now;
}
}
if (event == EVENT_LBUTTONUP)
{
x_change = y_change = false;
l_drawbox = false;
}
}
//画矩形
void DrawRect(Mat& img, Rect box)
{
RNG& rng = theRNG();
rectangle(img, box.tl(), box.br(), Scalar(rng.uniform(0, 255),
rng.uniform(0, 255), rng.uniform(0, 255))); //以(0,255)内均匀随机数作为矩形颜色
}
//p图
void ROI_linearBlending(Mat srcImg_1, Mat srcImg_2)
{
Mat imgROI1, imgROI2, temp1, temp2, dst;
srcImg_1.copyTo(temp1);
srcImg_2.copyTo(temp2);
imgROI1 = temp1(roi_sour);
imgROI2 = temp2(roi_mater);
addWeighted(imgROI1, 0., imgROI2, 1., 0., imgROI1);
imshow("dst", temp1);
imwrite("E:\\material\\result1.png", temp1);
}