起因:身处大学身不由己,总有些社团活动需要拉外联啥的,一拉外联就的朋友圈发广告,还不能发私密。为了一劳永逸的解决这个问题,自己用pyhton写了一个类似于p图的代码。
目的:将一张朋友圈截图中的某一矩形区域替换为另一图片中的矩形区域。
原理:利用opencv给图片加上滑动条以及实现截取区域。
使用方法:在source窗口截取矩形区域,在material窗口点击会自动勾出等大矩形区域,按空格保存图片。
不足:滑动条部分,两张图片是共享的,现在懒得改了。。。。
代码:
#include<opencv.hpp>
#include<iostream>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和heightint win_width, win_height; //window的width和heightint show_width, show_height; //窗口中图片的width和heightint 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 <<start<<"\n";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 (drawbox){now = Point(x, y);}}if (event == EVENT_LBUTTONUP){x_change = y_change = false;end = Point(x, y);width = end.x - start.x > 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);
}
素材:
结果: