[OpenCV实战]3 透明斗篷
目录
弄出哈利波特电影里一样效果的透明斗篷。也就是一个视频里,将红布弄成透明。类似下面的效果。

基本思想如下:
1寻找和存储背景帧。
2用颜色检测算法检测红色布。
3提取红色区域。
4背景帧红布区域替换当前帧红布区域。
1寻找和存储背景帧
算法关键思想是用背景像素替换与布相对应的当前帧像我们需提取和存储背景帧。背景帧检测算法很简单,实际上算不上背景帧建模算法。仅仅设定视频第31帧为背景图像。如果想了解背景帧提取算法可以看看背景建模算法,比如混合高斯背景建模算法。
C++代码如下:
Mat background;
//跳过前30帧
for (int i = 0; i < 30; i++)
{
cap >> background;
}
//沿Y轴翻转图像
flip(background, background, 1);
2红色区域检测
事实上基于RGB空间检测红色很困难,因为红色是RGB综合获得的。正确的方法是将图像从RGB颜色空间转到HSV空间。HSV对颜色的定义更接近人的视觉系统。对于颜色检测来说,HSV空间中,
HSV空间各个参数如下:
色调Hue:用角度度量,取值范围为0-度360度。可以认为0度对应于红色,120度对应于绿色,240度对应于蓝色。
饱和度Saturation:饱和度表示颜色的强度和纯度。例如,粉红色不如大红色饱和。
明度Value:表示颜色的明暗程度,取值范围为0.0(黑色)~1.0(白色)。

颜色仅由色调Hue决定。在OpenCV中色调不是0到360度,而被量化为0到180。
其中红色以0-30和150-180表示。
红色区域检测主要原理如下:
基于OpenCV中的inRange函数筛选颜色。其中红色Hue值的范围为0-10和170-180,以避免发现皮肤为红色。因为红布应该是高度饱和的红色。所以S值设定为120到255。明度设置为70到255。根据以上能够获得红色Hue值的范围为0-10和170-180d的两个红色区域。然后对其做并操作提取图像红色区域(红布区域)范围二值图像。所获得二值图像中白色部分(像素值为255)表示红布,黑色部分(像素值为0)表示背景。结果如下图所示:


c++代码如下:
//检测帧
Mat frame;
// Capture frame-by-frame
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty())
{
break;
}
//hsv图像
Mat hsv;
flip(frame, frame, 1);
cvtColor(frame, hsv, COLOR_BGR2HSV);
//红色区域1,红色区域2
Mat mask1, mask2;
//红色区域
Mat mask_red;
//背景区域
Mat mask_background;
//过滤颜色
//二值图,其中黑色0表示无红色,白色1表示红色区域。
inRange(hsv, Scalar(0, 120, 70), Scalar(10, 255, 255), mask1);
inRange(hsv, Scalar(170, 120, 70), Scalar(180, 255, 255), mask2);
mask_red = mask1 + mask2;
3提取红色区域
主要是通过红布区域范围二值图像提取红色区域图像(背景为黑色),并将背景图像中红布区域置为黑色。结果分别如下图所示


c++代码如下:
//去除噪声
Mat kernel = Mat::ones(3, 3, CV_32F);
morphologyEx(mask_red, mask_red, cv::MORPH_OPEN, kernel);
morphologyEx(mask_red, mask_red, cv::MORPH_DILATE, kernel);
//将mask_red中0,1互换,得到背景区域范围。
bitwise_not(mask_red, mask_background);
Mat res1, res2, final_output;
//从当前帧抠出背景区域res1,红布区域被涂成黑色。
bitwise_and(frame, frame, res1, mask_background);
//从背景帧提取红布区域覆盖的背景res2
bitwise_and(background, background, res2, mask_red);
4背景帧红布区域替换当前帧红布区域。
最后通过addWeighted函数将上面两张图融合。这样就能弄出透明的效果。只能针对特定视频,所用视频及代码见:
https://download.csdn.net/download/luohenyj/11001759
https://github.com/luohenyueji/OpenCV-Practical-Exercise
如果没有积分(系统自动设定资源分数)看看参考链接。我搬运过来的,大修改没有。pch是预编译文件。视频有红布出现在第250帧后。
5工程代码
实际上这种方法只有在特定场合实用,来练手还是挺适合的。全部代码如下:
C++版本
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
//打开视频
VideoCapture cap("video/detect.mp4");
// 检查视频是否打开
if (!cap.isOpened())
{
cout << "Error opening video stream or file" << endl;
return -1;
}
Mat background;
//跳过前30帧
for (int i = 0; i < 30; i++)
{
cap >> background;
}
//沿Y轴翻转图像
flip(background, background, 1);
//红布第251帧才出现,跳过前250帧
for (int i = 0; i < 220; i++)
{
Mat frame_slip;
cap >> frame_slip;
continue;
}
//图像读取
while (1)
{
//检测帧
Mat frame;
// Capture frame-by-frame
cap >> frame;
// If the frame is empty, break immediately
if (frame.empty())
{
break;
}
//hsv图像
Mat hsv;
flip(frame, frame, 1);
cvtColor(frame, hsv, COLOR_BGR2HSV);
//红色区域1,红色区域2
Mat mask1, mask2;
//红色区域
Mat mask_red;
//背景区域
Mat mask_background;
//过滤颜色
//二值图,其中黑色0表示无红色,白色1表示红色区域。
inRange(hsv, Scalar(0, 120, 70), Scalar(10, 255, 255), mask1);
inRange(hsv, Scalar(170, 120, 70), Scalar(180, 255, 255), mask2);
mask_red = mask1 + mask2;
//去除噪声
Mat kernel = Mat::ones(3, 3, CV_32F);
morphologyEx(mask_red, mask_red, cv::MORPH_OPEN, kernel);
morphologyEx(mask_red, mask_red, cv::MORPH_DILATE, kernel);
//将mask_red中0,1互换,得到背景区域范围。
bitwise_not(mask_red, mask_background);
Mat res1, res2, final_output;
//从当前帧抠出背景区域res1,红布区域被涂成黑色。
bitwise_and(frame, frame, res1, mask_background);
//从背景帧提取红布区域覆盖的背景res2
bitwise_and(background, background, res2, mask_red);
addWeighted(res1, 1, res2, 1, 0, final_output);
//展示图像
imshow("Magic !!!", final_output);
// Press ESC on keyboard to exit
char c = (char)waitKey(1);
if (c == 27)
{
break;
}
}
return 0;
}
python代码:
import cv2
import numpy as np
import time
# Creating an VideoCapture object
# This will be used for image acquisition later in the code.
cap = cv2.VideoCapture('video/detect.mp4')
if cap.isOpened:
print("your video is opened")
# We give some time for the camera to setup
time.sleep(3)
count = 0
background=0
# Capturing and storing the static background frame
for i in range(60):
ret,background = cap.read()
background = np.flip(background,axis=1)
#跳帧
for i in range(200):
slip_frame = cap.read()
while(cap.isOpened()):
ret, img = cap.read()
if not ret:
break
count+=1
img = np.flip(img,axis=1)
# Converting the color space from BGR to HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Generating mask to detect red color
lower_red = np.array([0,120,70])
upper_red = np.array([10,255,255])
mask1 = cv2.inRange(hsv,lower_red,upper_red)
lower_red = np.array([170,120,70])
upper_red = np.array([180,255,255])
mask2 = cv2.inRange(hsv,lower_red,upper_red)
mask1 = mask1+mask2
# Refining the mask corresponding to the detected red color
mask1 = cv2.morphologyEx(mask1, cv2.MORPH_OPEN, np.ones((3,3),np.uint8),iterations=2)
mask1 = cv2.dilate(mask1,np.ones((3,3),np.uint8),iterations = 1)
mask2 = cv2.bitwise_not(mask1)
# Generating the final output
res1 = cv2.bitwise_and(background,background,mask=mask1)
res2 = cv2.bitwise_and(img,img,mask=mask2)
final_output = cv2.addWeighted(res1,1,res2,1,0)
cv2.imshow('Magic !!!',final_output)
k = cv2.waitKey(10)
if k == 27:
break
参考
https://www.learnopencv.com/invisibility-cloak-using-color-detection-and-segmentation-with-opencv/
[OpenCV实战]3 透明斗篷的更多相关文章
- OpenCV实战:人脸关键点检测(FaceMark)
Summary:利用OpenCV中的LBF算法进行人脸关键点检测(Facial Landmark Detection) Author: Amusi Date: 2018-03-20 ...
- [OpenCV实战]50 用OpenCV制作低成本立体相机
本文主要讲述利用OpenCV制作低成本立体相机以及如何使用OpenCV创建3D视频,准确来说是模仿双目立体相机,我们通常说立体相机一般是指双目立体相机,就是带两个摄像头的那种(目就是指眼睛,双目就是两 ...
- [OpenCV实战]49 对极几何与立体视觉初探
本文主要介绍对极几何(Epipolar Geometry)与立体视觉(Stereo Vision)的相关知识.对极几何简单点来说,其目的就是描述是两幅视图之间的内部对应关系,用来对立体视觉进行建模,实 ...
- [OpenCV实战]48 基于OpenCV实现图像质量评价
本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...
- 使用opencv为没有透明通道的图像加入透明通道
在图像处理中,我们经常需要处理带透明通道的图片,比如为图片或视频添加水印,为图片或视频添加字幕.贴图等.然而,我们的素材图片未必总是带有透明通道.比如,素材的背景本该透明的地方,却是黑色和白色.有时, ...
- opencv实战——图像矫正算法深入探讨
摘要 在机器视觉中,对于图像的处理有时候因为放置的原因导致ROI区域倾斜,这个时候我们会想办法把它纠正为正确的角度视角来,方便下一步的布局分析与文字识别,这个时候通过透视变换就可以取得比较好的裁剪效果 ...
- 用python进行OpenCV实战之用OpenCV3实现图片载入、显示和储存(argparse详细解释)
将下面文档存为load_display_save.py #-*- coding:utf-8 -*- ap = argparse.ArgumentParser() ap.add_argument(&qu ...
- [OpenCV实战]45 基于OpenCV实现图像哈希算法
目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...
- [OpenCV实战]8 深度学习目标检测网络YOLOv3的训练
目录 1 数据集 1.1 下载openImages雪人数据[约1.5小时] 1.2 训练集测试集拆分 2 Darknet 2.1 下载并构建Darknet 2.2 修改代码以定期保存模型文件 2.3 ...
随机推荐
- Linux安装oracle 12C
安装虚拟系统CentOS6.5,分配给至少1G的内存,其他条件适当高些,具体参考官方文档 环境准备 vim /etc/profileexport JAVA_HOME=/opt/jdk1.7.0_79e ...
- Codeforces Round #801 (Div. 2) C(规律证明)
Codeforces Round #801 (Div. 2) C(规律证明) 题目链接: 传送门QAQ 题意: 给定一个\(n * m\)的矩阵,矩阵的每个单元的值为1或-1,问从\((1,1)\)开 ...
- Linux实战笔记__Ubuntu20.04上搭建Vulhub漏洞环境
安装python3和pip3 安装docker 安装docker-compose 上传解压vulhub-master.zip 启动漏洞环境 进入某漏洞目录,执行docker-compose up -d ...
- 银行ATM存取款系统(C语言实现)
这里使用的运行工具是DEV C++.老铁们一定要看仔细了.是DEV C++ 仅供借鉴:这个是大一时期写的.大四的时候整理了一下(本人C语言学的也不太好).肯定很多不足和存在漏洞的地方.仅供借鉴.仅供借 ...
- 支持JDK19虚拟线程的web框架,之一:体验
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于虚拟线程 随着JDK19 GA版本的发布,虚拟线程 ...
- 详解AQS中的condition源码原理
摘要:condition用于显式的等待通知,等待过程可以挂起并释放锁,唤醒后重新拿到锁. 本文分享自华为云社区<AQS中的condition源码原理详细分析>,作者:breakDawn. ...
- 一次SpringBoot版本升级,引发的血案
前言 最近项目组升级了SpringBoot版本,由之前的2.0.4升级到最新版本2.7.5,却引出了一个大Bug. 到底是怎么回事呢? 1.案发现场 有一天,项目组的同事反馈给我说,我之前有个接口在新 ...
- 【笔记】CF1607F Robot on the Board 2 及相关
题目传送门 记忆化搜索 首先,这题 \(10000\) 组 \(2000\times 2000\) 的数据直接爆搜肯定会超时.想到,如果一个点的答案已经被更新过,之后走到这个点能再多走的点也就确定了, ...
- 【云原生 · Docker】Docker虚拟化技术
1.Docker入门简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化. 容器是完全使用沙箱 ...
- python opencv制作隐藏图片
前言 隐藏图片就是在白色背景和黑色背景显示出不同的图片,之前qq可以显示,现在好像也不行了,原因就是原来的qq,在发出来默认是白色背景,而点开后是黑色背景.但是这个原理还是挺有意思的,所以简单的研究了 ...