OpenCV-3之draw_shape

本文介绍了使用Python结合OpenCV库进行图像处理的方法,详细展示了如何利用cv2.line、cv2.circle、cv2.rectangle等函数绘制直线、圆、矩形等基本形状,并介绍了如何用cv2.putText函数为图像添加文本。

1、cv2.line

import cv2
img = cv2.imread(r"img/1.jpg")

cv2.line(img, pt1=(100, 30), pt2=(210, 180), color=(0, 0, 255), thickness=2) 
cv2.imshow("pic show", img)
cv2.waitKey(0)

2、cv2.circle:thickness=-1,内部填充

import cv2
img = cv2.imread(r"img/1.jpg")

cv2.circle(img, center=(50, 50), radius=30, color=(0, 0, 255), thickness=2) 
cv2.imshow("pic show", img)
cv2.waitKey(0)

3、cv2.rectangle:thickness=-1,内部填充

cv2.rectangle(img, pt1=(100, 30), pt2=(210, 180), color=(0, 0, 255), thickness=2)

4、cv2.ellipse:thickness=-1,内部填充

cv2.ellipse(img, center=(100, 100), axes=(100, 50), angle=0, startAngle=0, endAngle=360, color=(255, 0, 0), thickness=-1)

5、cv2.polylines:[pts],否则点不连城线,thickness不能取负数

pts = np.array([[10, 5], [50, 10], [70, 20], [20, 30]], np.int32)
pts = pts.reshape((-1, 1, 2))  # shape[4, 1, 2]
cv2.polylines(img, [pts], isClosed=True, color=(0, 0, 255), thickness=2)

6、cv2.putText

# org:Bottom-left corner of the text string in the image
# lineType=cv2.LINE_AA:抗锯齿
cv2.putText(img, text='beautiful girl', org=(10, 30), fontFace=cv2.FONT_HERSHEY_SIMPLEX, 
            fontScale=1, color=(0, 0, 255), thickness=1, lineType=cv2.LINE_AA)
void ImageWidget::SeamlessClone() { if (source_window_ == NULL) return; // 获取源图和目标图 QImage* src_img = source_window_->imagewidget_->image(); QImage* dst_img = image_; // 选择区域 int xsrc = source_window_->imagewidget_->point_start_.x(); int ysrc = source_window_->imagewidget_->point_start_.y(); int w = source_window_->imagewidget_->point_end_.x() - xsrc; int h = source_window_->imagewidget_->point_end_.y() - ysrc; QRect rect_src(xsrc, ysrc, w, h); // 转换为 OpenCV Mat Mat src = QImage2Mat(src_img->copy(rect_src)); Mat dst = QImage2Mat(*dst_img); // 创建 mask(全部白色) Mat mask(src.rows, src.cols, CV_8UC1, Scalar::all(255)); // 设置融合中心:以目标区域选择矩形中心为例 Point center(point_start_.x() + w / 2, point_start_.y() + h / 2); // 执行无缝克隆 Mat result; seamlessClone(src, dst, mask, center, result, NORMAL_CLONE); // 更新图像 *image_ = Mat2QImage(result); update(); std::cout << "Seamless clone finished" << std::endl; } void ImageWidget::mousePressEvent(QMouseEvent* mouseevent) { if (Qt::LeftButton == mouseevent->button()) { switch (draw_status_) { case kChoose: is_choosing_ = true; point_start_ = point_end_ = mouseevent->pos(); break; case kPaste: { is_pasting_ = true; // Start point in object image int xpos = mouseevent->pos().rx(); int ypos = mouseevent->pos().ry(); // Start point in source image int xsourcepos = source_window_->imagewidget_->point_start_.rx(); int ysourcepos = source_window_->imagewidget_->point_start_.ry(); // Width and Height of rectangle region int w = source_window_->imagewidget_->point_end_.rx() - source_window_->imagewidget_->point_start_.rx() + 1; int h = source_window_->imagewidget_->point_end_.ry() - source_window_->imagewidget_->point_start_.ry() + 1; // Paste if ((xpos + w < image_->width()) && (ypos + h < image_->height())) { for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { image_->setPixel(xpos + i, ypos + j, source_window_->imagewidget_->image()->pixel(xsourcepos + i, ysourcepos + j)); } } } } update(); break; default: break; } } } void ImageWidget::mouseMoveEvent(QMouseEvent* mouseevent) { switch (draw_status_) { case kChoose: // Store point position for rectangle region if (is_choosing_) { point_end_ = mouseevent->pos(); } break; case kPaste: // Paste rectangle region to object image if (is_pasting_) { //point_start_ = mouseevent->pos(); // Start point in object image int xpos = mouseevent->pos().rx(); int ypos = mouseevent->pos().ry(); // Start point in source image int xsourcepos = source_window_->imagewidget_->point_start_.rx(); int ysourcepos = source_window_->imagewidget_->point_start_.ry(); // Width and Height of rectangle region int w = source_window_->imagewidget_->point_end_.rx() - source_window_->imagewidget_->point_start_.rx() + 1; int h = source_window_->imagewidget_->point_end_.ry() - source_window_->imagewidget_->point_start_.ry() + 1; // Paste if ((xpos > 0) && (ypos > 0) && (xpos + w < image_->width()) && (ypos + h < image_->height())) { // Restore image *(image_) = *(image_backup_); // Paste for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { image_->setPixel(xpos + i, ypos + j, source_window_->imagewidget_->image()->pixel(xsourcepos + i, ysourcepos + j)); } } } } default: break; } update(); } void ImageWidget::mouseReleaseEvent(QMouseEvent* mouseevent) { switch (draw_status_) { case kChoose: if (is_choosing_) { point_end_ = mouseevent->pos(); is_choosing_ = false; draw_status_ = kNone; } case kPaste: if (is_pasting_) { is_pasting_ = false; draw_status_ = kNone; } default: break; } update(); } void MainWindow::SeamlessClone() { // 当前窗口为目标图 ChildWindow* dest_window = GetChildWindow(); if (!dest_window) return; // 源窗口为之前 ChooseRect 选中的窗口 if (!child_source_) { QMessageBox::warning(this, tr("Warning"), tr("Please choose a source region first.")); return; } // 调用 ImageWidget 的无缝克隆接口 dest_window->imagewidget_->set_source_window(child_source_); dest_window->imagewidget_->SeamlessClone(); } 现在已经实现了简单粘贴,怎么把粘贴过来的部分在目标图像上进行无缝克隆
最新发布
11-11
<think>我们已实现简单粘贴功能,现在需要将粘贴部分在目标图像上进行无缝克隆。根据引用[3],OpenCV提供了无缝克隆函数cv::seamlessClone,该函数能够将源图像中的对象融合到目标图像中,使边界过渡自然。 ### 步骤说明 1. **准备输入**: - `src`: 源图像(包含要粘贴的对象) - `dst`: 目标图像(背景图像) - `mask`: 二值掩码,指定源图像中哪些区域需要克隆(对象区域为白色,背景为黑色) - `p`: 目标图像中放置对象的位置(通常为对象中心点) 2. **选择克隆方法**: - `cv.NORMAL_CLONE`: 保留源图像的纹理和颜色,适合背景相似的情况 - `cv.MIXED_CLONE`: 混合源和目标的颜色纹理,适合背景有明显差异的情况 - `cv.MONOCHROME_TRANSFER`: 仅复制对象的亮度信息,颜色与目标保持一致 3. **调用函数**: ```python blend = cv2.seamlessClone(src, dst, mask, p, flags) ``` ### 代码示例(Python) ```python import cv2 import numpy as np # 1. 读取源图像和目标图像 src = cv2.imread("airplane.jpg") # 包含要粘贴的对象 dst = cv2.imread("sky.jpg") # 背景图像 # 2. 创建掩码(假设对象在源图像中心,需根据实际调整) mask = np.zeros(src.shape[:2], dtype=np.uint8) # 假设对象位于矩形区域 (x1,y1) 到 (x2,y2) mask[y1:y2, x1:x2] = 255 # 3. 确定粘贴位置(目标图像的中心) h, w = src.shape[:2] center = (w//2, h//2) # 示例:目标图像中心 # 4. 执行无缝克隆 blend = cv2.seamlessClone(src, dst, mask, center, cv2.MIXED_CLONE) # 5. 保存结果 cv2.imwrite("result.jpg", blend) ``` ### 关键点说明 - **掩码生成**:实际应用中,掩码可通过图像分割(如GrabCut)或手动标注获取精确对象轮廓。 - **位置选择**:点`p`应位于目标图像中希望放置对象的位置(通常是对象中心)。 - **方法选择**: - 若源与目标背景差异大,推荐`MIXED_CLONE`; - 若需保留源对象颜色纹理,用`NORMAL_CLONE`; - 若需对象亮度融合且颜色匹配目标,用`MONOCHROME_TRANSFER`。 §§相关问题§§ 1. 如何自动生成精确的对象掩码? 2. 无缝克隆在哪些场景下效果可能不佳? 3. 除了OpenCV,还有哪些库支持图像无缝克隆? </think>### 在OpenCV中实现无缝克隆的方法 您已实现简单粘贴功能,要升级为无缝克隆效果,请按照以下步骤操作(基于OpenCVcv::seamlessClone函数): #### 核心步骤 1. **准备输入参数**: - `src`: 源图像(要粘贴的对象) - `dst`: 目标图像(背景图像) - `mask`: 二值掩码(标记对象区域) - `p`: 目标图像中的粘贴位置(坐标点) - `flags`: 克隆模式(选择融合算法) 2. **克隆模式选择**(关键参数): ```python flags = { 0: cv2.NORMAL_CLONE, # 保留源图像纹理 1: cv2.MIXED_CLONE, # 混合源/目标纹理(推荐) 2: cv2.MONOCHROME_TRANSFER # 仅复制亮度信息 } ``` #### Python实现代码 ```python import cv2 import numpy as np def seamless_paste(src_img, dst_img, mask, position_x, position_y): """实现无缝克隆""" # 创建掩码(单通道) if mask.ndim == 3: mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) # 设置目标位置点 paste_point = (position_x, position_y) # 执行无缝克隆(推荐MIXED_CLONE模式) result = cv2.seamlessClone( src=src_img, dst=dst_img, mask=mask, p=paste_point, flags=cv2.MIXED_CLONE # 最佳色彩融合 ) return result # 使用示例 src = cv2.imread("object.png") # 要粘贴的对象 dst = cv2.imread("background.jpg") # 背景图像 mask = cv2.imread("mask.png", 0) # 对象的二值掩码 # 在背景坐标(100,200)处无缝克隆 result_image = seamless_paste(src, dst, mask, 100, 200) cv2.imwrite("seamless_result.jpg", result_image) ``` #### 关键要点说明 1. **掩码生成**: - 使用阈值分割或GrabCut算法生成精确对象掩码 - 掩码必须是单通道二值图像(对象区域为255,背景为0) 2. **位置对齐**: - 确保粘贴点`p`与目标图像比例协调 - 推荐计算对象中心点坐标: $$ p_x = \frac{\text{目标宽度}}{2}, \quad p_y = \frac{\text{目标高度}}{3} $$ 3. **模式选择**: - `MIXED_CLONE`(混合克隆):最佳自然融合效果,保留源纹理同时适应目标光照[^3] - `NORMAL_CLONE`:适合纯色背景 - `MONOCHROME_TRANSFER`:保留形状但匹配目标颜色 #### 效果对比 | 方法 | 边界处理 | 光照适应性 | 适用场景 | |------|----------|------------|----------| | 简单粘贴 | 硬边缘 | 无 | 临时预览 | | 无缝克隆 | 渐变融合 | 自动匹配 | 合成渲染 | > 实际案例:将飞机融入云层时,无缝克隆会**自动调整**飞机边缘的亮度/色调,使其与云层的光照条件匹配,消除不自然的切割感[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值