OpenCV开发笔记(八十二):两图拼接使用渐进色蒙版场景过渡缝隙

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/143432922

长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

OpenCV开发专栏(点击传送门)

上一篇:《OpenCV开发笔记(八十一):通过棋盘格使用鱼眼方式标定相机内参矩阵矫正摄像头图像》
下一篇:持续补充中…


前言

  对于图像拼接,前面探讨了通过基于Stitcher进行拼接过渡和基于特征点进行拼接过渡,这2个过渡的方式是摄像头拍摄角度和方向不应差距太大。
  对于特定的场景,本身摄像头拍摄角度差距较大,拉伸变换后也难做到完美的缝隙拼接,这个时候使用渐近过渡反倒是最好的。


Demo

  单独蒙版
   在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  蒙版过渡,这里只是根据图来,其实可对每个像素对于第一张图为系数k,而第二张为255-k,实现渐近过渡。
  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

  直接使用第一张蒙版优化
  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述


准本蒙版

  蒙版可以混合,也可以分开,为了让读者更好的深入理解原理,这里都使用:
  找个工具,造单色渐进色,红色蒙版,只是r通道,bga都为0
  在这里插入图片描述

  (注意:使用rgba四通道)
  在这里插入图片描述

  (上面这张图,加了边框,导致了“入坑二”打印像素值不对)
  在这里插入图片描述

  由于工具渐进色无法叠层,这个工具无法实现rgba不同向渐进色再一张图(横向、纵向、斜向),更改了方式,每个使用一张图:
  为了方便,不管a通道了,直接a为100%(255)。
  在这里插入图片描述

  再弄另外一个通道的:
  在这里插入图片描述

  在这里使用工具就只能单独一张了:
  在这里插入图片描述


一个蒙版图的过渡实例

步骤一:打开图片和蒙版

  在这里插入图片描述

   cv::Mat matLeft = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/29.jpg");cv::Mat matRight = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/30.jpg");cv::Mat matMask1 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/37.png", cv::IMREAD_UNCHANGED);cv::Mat matMask2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/38.png", cv::IMREAD_UNCHANGED);cv::Mat matMask3 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/39.png", cv::IMREAD_UNCHANGED);cv::Mat matMask4 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/40.png", cv::IMREAD_UNCHANGED);

步骤二:将蒙版变成和原图一样大小

  在这里插入图片描述

    cv::resize(matLeft, matLeft, cv::Size(0, 0), 0.5, 0.5);cv::resize(matRight, matRight, cv::Size(0, 0), 0.5, 0.5);cv::resize(matMask1, matMask1, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask2, matMask2, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask3, matMask3, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask4, matMask4, cv::Size(matLeft.cols, matLeft.rows));

步骤三:底图

  由于两张图虽然是同样大小,但是其不是按照整体拼接后的大小,所以需要假设一个拼接后的大小的底图。
  在这里插入图片描述

    // 底图,扩大500横向,方便移动cv::Mat matResult = cv::Mat(matLeft.rows, matLeft.cols + 500, CV_8UC3);

步骤四:原图融合

  在这里插入图片描述

        // 副本,每次都要重新清空来调整cv::Mat matResult2 = matResult.clone();
#if 1// 第一张图,直接比例赋值,因为底图为0for(int row = 0; row < matLeft.rows; row++){for(int col = 0; col < matLeft.cols; col++){double r = matMask1.at<cv::Vec4b>(row, col)[2] / 255.0f;
//                double r = matMask2.at<cv::Vec4b>(row, col)[1] / 255.0f;
//                double r = matMask3.at<cv::Vec4b>(row, col)[0] / 255.0f;
//                double r = matMask4.at<cv::Vec4b>(row, col)[0] / 255.0f;matResult2.at<cv::Vec3b>(row, col)[0] = (matLeft.at<cv::Vec3b>(row, col)[0] * r);matResult2.at<cv::Vec3b>(row, col)[1] = (matLeft.at<cv::Vec3b>(row, col)[1] * r);matResult2.at<cv::Vec3b>(row, col)[2] = (uchar)(matLeft.at<cv::Vec3b>(row, col)[2] * r);}}
#endif

步骤五:另外一张图的融合

  在这里插入图片描述

#if 1// 第二张图,加法,因为底图为原图了for(int row = 0; row < matRight.rows; row++){for(int col = 0; col < matRight.cols; col++){double g = matMask2.at<cv::Vec4b>(row, col)[1] / 255.0f;// 偏移了x坐标matResult2.at<cv::Vec3b>(row, col + x)[0] += matRight.at<cv::Vec3b>(row, col)[0] * g;matResult2.at<cv::Vec3b>(row, col + x)[1] += matRight.at<cv::Vec3b>(row, col)[1] * g;matResult2.at<cv::Vec3b>(row, col + x)[2] += matRight.at<cv::Vec3b>(row, col)[2] * g;}}
#endif

步骤六(与步骤五互斥):优化的融合

  在这里插入图片描述

#if 1// 第二张图,加法,因为底图为原图了(优化)for(int row = 0; row < matRight.rows; row++){for(int col = 0; col < matRight.cols; col++){double r2;if(x + col <= matLeft.cols){r2 = (255 - matMask1.at<cv::Vec4b>(row, col + x)[2]) / 255.0f;}else{r2 = 1.0f;}// 偏移了x坐标matResult2.at<cv::Vec3b>(row, col + x)[0] += matRight.at<cv::Vec3b>(row, col)[0] * r2;matResult2.at<cv::Vec3b>(row, col + x)[1] += matRight.at<cv::Vec3b>(row, col)[1] * r2;matResult2.at<cv::Vec3b>(row, col + x)[2] += matRight.at<cv::Vec3b>(row, col)[2] * r2;}}
#endif

函数原型

  手码的像素算法,没有什么高级函数。


Demo源码

void OpenCVManager::testMaskSplicing()
{cv::Mat matLeft = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/29.jpg");cv::Mat matRight = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/30.jpg");cv::Mat matMask1 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/37.png", cv::IMREAD_UNCHANGED);cv::Mat matMask2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/38.png", cv::IMREAD_UNCHANGED);cv::Mat matMask3 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/39.png", cv::IMREAD_UNCHANGED);cv::Mat matMask4 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/40.png", cv::IMREAD_UNCHANGED);#if 0// 打印通道数和数据类型// ..\openCVDemo\modules\openCVManager\OpenCVManager.cpp 9166 "2024-10-31 20:07:42:619" 4 24 24LOG << matMask.channels() << matMask.type() << CV_8UC4; // 4 24// 打印mask蒙版行像素,隔一定行数打一次for(int row = 0; row < matMask.rows; row += 10){for(int col = 100; col < matMask.cols; col++){int r = matMask.at<cv::Vec4b>(row, col)[2];int g = matMask.at<cv::Vec4b>(row, col)[1];int b = matMask.at<cv::Vec4b>(row, col)[0];int a = matMask.at<cv::Vec4b>(row, col)[3];LOG << "row:" << row << ", col:" << col << "r(rgba):" << r << g << b << a;break;}}
#endif// 图片较大,缩为原来的0.5倍cv::resize(matLeft, matLeft, cv::Size(0, 0), 0.5, 0.5);cv::resize(matRight, matRight, cv::Size(0, 0), 0.5, 0.5);cv::resize(matMask1, matMask1, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask2, matMask2, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask3, matMask3, cv::Size(matLeft.cols, matLeft.rows));cv::resize(matMask4, matMask4, cv::Size(matLeft.cols, matLeft.rows));// 底图,扩大500横向,方便移动cv::Mat matResult = cv::Mat(matLeft.rows, matLeft.cols + 500, CV_8UC3);// 第一张图int key = 0;int x = 0;while(true){// 副本,每次都要重新清空来调整cv::Mat matResult2 = matResult.clone();
#if 1// 第一张图,直接比例赋值,因为底图为0for(int row = 0; row < matLeft.rows; row++){for(int col = 0; col < matLeft.cols; col++){double r = matMask1.at<cv::Vec4b>(row, col)[2] / 255.0f;
//                double r = matMask2.at<cv::Vec4b>(row, col)[1] / 255.0f;
//                double r = matMask3.at<cv::Vec4b>(row, col)[0] / 255.0f;
//                double r = matMask4.at<cv::Vec4b>(row, col)[0] / 255.0f;matResult2.at<cv::Vec3b>(row, col)[0] = (matLeft.at<cv::Vec3b>(row, col)[0] * r);matResult2.at<cv::Vec3b>(row, col)[1] = (matLeft.at<cv::Vec3b>(row, col)[1] * r);matResult2.at<cv::Vec3b>(row, col)[2] = (uchar)(matLeft.at<cv::Vec3b>(row, col)[2] * r);}}
#endif
#if 0// 第二张图,加法,因为底图为原图了for(int row = 0; row < matRight.rows; row++){for(int col = 0; col < matRight.cols; col++){double g = matMask2.at<cv::Vec4b>(row, col)[1] / 255.0f;// 偏移了x坐标matResult2.at<cv::Vec3b>(row, col + x)[0] += matRight.at<cv::Vec3b>(row, col)[0] * g;matResult2.at<cv::Vec3b>(row, col + x)[1] += matRight.at<cv::Vec3b>(row, col)[1] * g;matResult2.at<cv::Vec3b>(row, col + x)[2] += matRight.at<cv::Vec3b>(row, col)[2] * g;}}
#endif
#if 1// 第二张图,加法,因为底图为原图了(优化)for(int row = 0; row < matRight.rows; row++){for(int col = 0; col < matRight.cols; col++){double r2;if(x + col <= matLeft.cols){r2 = (255 - matMask1.at<cv::Vec4b>(row, col + x)[2]) / 255.0f;}else{r2 = 1.0f;}// 偏移了x坐标matResult2.at<cv::Vec3b>(row, col + x)[0] += matRight.at<cv::Vec3b>(row, col)[0] * r2;matResult2.at<cv::Vec3b>(row, col + x)[1] += matRight.at<cv::Vec3b>(row, col)[1] * r2;matResult2.at<cv::Vec3b>(row, col + x)[2] += matRight.at<cv::Vec3b>(row, col)[2] * r2;}}
#endif//        cv::imshow("matMask1", matMask1);
//        cv::imshow("matLeft", matLeft);cv::imshow("matResult2", matResult2);key = cv::waitKey(0);if(key == 'a'){x--;if(x < 0){x = 0;}}else if(key == 'd'){x++;if(x + matRight.cols > matResult2.cols){x = matResult2.cols - matRight.cols;}}else if(key == 'q'){break;}}
}

工程模板v1.72.0

  在这里插入图片描述


入坑

入坑一:读取通道rgba失败

问题:读取通道rgba失败

  在这里插入图片描述

原因

  是uchar,转换成byte,而不是int
  在这里插入图片描述

解决

  在这里插入图片描述

  在这里插入图片描述

入坑二:读取通道一直是0,0,0,255

问题

  读取通道一直是0,0,0,255。
  在这里插入图片描述

原因

  弄了张图,还是255,然后发现是为了截图更清楚,弄了个边框,而我们打印正好是打印了0位置。
  在这里插入图片描述

  在这里插入图片描述

解决

  最终是要去掉边框,没边框就是空看不出,如下图:
  在这里插入图片描述

  在这里插入图片描述

入坑三:过渡有黑线赋值不对

问题

  直接位置赋值,出现条纹
  在这里插入图片描述

  在这里插入图片描述

原因

  类型是vec4b
  在这里插入图片描述

解决

  在这里插入图片描述

  在这里插入图片描述

入坑四:原图融合比例有黑线

问题

  在这里插入图片描述

原因

  跟上面一样,mask蒙版是rgba的,需要vec4b
  在这里插入图片描述

解决

  在这里插入图片描述

  在这里插入图片描述


上一篇:《OpenCV开发笔记(八十一):通过棋盘格使用鱼眼方式标定相机内参矩阵矫正摄像头图像》
下一篇:持续补充中…


本文章博客地址:https://hpzwl.blog.csdn.net/article/details/143432922

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/58871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity程序化生成地形

制作地形&#xff1a; 绘制方块逐个绘制方块并加噪波高度删除Gizmos和逐个绘制 1.draw quad using System.Collections; using System.Collections.Generic; using UnityEngine;[RequireComponent(typeof(MeshFilter))] public class mesh_generator : MonoBehaviour {Mesh m…

基于MoviNet检测视频中危险暴力行为

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【Faster & Mask R-CNN模型实现啤酒瓶瑕疵检测】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生…

Java项目实战II基于Java+Spring Boot+MySQL的桂林旅游景点导游平台(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 基于Java、…

每日读则推(十四)——Meta Movie Gen: the most advanced media foundation models to-date

premiere n.首映,首次公演 v.首次公演(戏剧、音乐、电影) a.首要的,最早的 Today we’re premiering Meta Movie Gen: the most advanced media foundation models to-date. 迄今,到现在为止 …

整数越界详解

目录 一、整数类型的范围 二、整数越界的原因 三、整数越界的示例 1.算术运算导致的整数越界 2.位运算导致的整数越界 3.数据类型转换导致的整数越界 四、整数越界的解决方法 在编程中&#xff0c;整数越界是一个需要特别注意的问题。当整数的计算结果超出了其所能表…

深度学习基础知识-编解码结构理论超详细讲解

编解码结构&#xff08;Encoder-Decoder&#xff09;是一种应用广泛且高效的神经网络架构&#xff0c;最早用于序列到序列&#xff08;Seq2Seq&#xff09;任务&#xff0c;如机器翻译、图像生成、文本生成等。随着深度学习的发展&#xff0c;编解码结构不断演变出多种模型变体…

Yolo系列 Yolo v4简介

目录 简介 YOLOv4的特点 1、数据增强&#xff1a;马赛克数据增强&#xff08;Mosaic Data Augmentation&#xff09; 2、 防止过拟合的方法DropBlock 3、标签平滑&#xff08;Label Smoothing&#xff09; 4、损失函数 &#xff1a;GIOU损失、DIOU损失、CIOU损失 &#x…

C语言的数组地址 数组的遍历与练习

1.int main(void) { int a[5] { 10,20,30,40,50 };//数组间的元素地址相连的 int* p; printf("%d\n", &a[0]); printf("%d\n", &a[1]); printf("%d\n", &a[2]); printf("%d\n", &a[3]); …

Python实现SSA智能麻雀搜索算法优化XGBoost-MLP回归模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后关注获取。 1.项目背景 随着大数据技术的迅猛发展&#xff0c;机器学习模型在各行各业的应用越来越广泛。特别是在回归任务…

nginx 设置多个代理服务器(nginx多代理)

修改配置文件 nginx.conf 修改前的内容&#xff0c;如下&#xff1a; worker_processes 1;events {worker_connections 1024; }http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;server {listen 80…

如何找到网上爆款内容,快速复制扩大品牌声量

社媒内容爆款复制是现代营销中的一个重要策略&#xff0c;它对于提升品牌声量、曝光度和知名度具有显著效果。 首先什么是爆款&#xff1f; 爆款内容指的是在社交媒体或其他在线平台上迅速获得大量关注、分享和讨论的内容。 准确、及时找到这部分品牌相关的爆款内容&#xf…

2024年10月文章一览

2024年10月编程人总共更新了21篇文章&#xff1a; 1.2024年9月文章一览 2.《Programming from the Ground Up》阅读笔记&#xff1a;p147-p180 3.《Programming from the Ground Up》阅读笔记&#xff1a;p181-p216 4.《Programming from the Ground Up》阅读笔记&#xff…

Git连接码云-保姆级教学(连接Gitee失败的解决)

Git介绍 码云连接 一、Git介绍 二、Git的工作机制 下载链接&#xff1a;Git - 下载软件包 三、使用步骤 创建一个wss的文件夹&#xff0c;作为‘工作空间’ 四、连接码云账号 五、连接Gitee失败的解决方法 一、Git介绍 Git是一个免费的、开源的分布式版本控制…

KINGBASE部署

环境&#xff1a;x86_64 系统&#xff1a;centos7.9 数据库–版本&#xff1a;KingbaseES_V008R006C008B0014_Lin64_install 授权文件–版本&#xff1a;V008R006-license-企业版-90天 一 前置要求 1.1. 硬件环境要求 KingbaseES支持通用X86_64、龙芯、飞腾、鲲鹏等国产C…

Java并发常见面试题总结(下)

Map&#xff08;重要&#xff09; HashMap 和 Hashtable 的区别 线程是否安全&#xff1a; HashMap 是非线程安全的&#xff0c;Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。&#xff08;如果你要保证线程安全的话就使用 ConcurrentHashMa…

Java - 免费图文识别_Java_免费_图片转文字_文字识别_spring ai_spring ai alibaba

本文主要是介绍借助阿里云免费的大模型额度来做高质量的图转文识别&#xff0c;图片转文字&#xff0c;或者文字识别都可以使用&#xff0c;比传统的OCR模式要直接和高效很多 。 本文使用的技术是spring ai qwen vl 。 Qwen vl有 100万Token 免费额度&#xff0c;可以用来免费…

基于边缘计算的智能门禁系统架构设计分析

案例 阅读以下关于 Web 系统架构设计的叙述&#xff0c;回答问题1至问题3。 【说明】 某公司拟开发一套基于边缘计算的智能门禁系统&#xff0c;用于如园区、新零售、工业现场等存在来访被访业务的场景。来访者在来访前&#xff0c;可以通过线上提前预约的方式将自己的个人信息…

基于SpringBoot+Vue的购物商城系统【前后端分离】

基于SpringBootVue的购物商城系统设计与实现 摘要 随着互联网技术的不断发展&#xff0c;线上购物已经成为人们日常生活中不可或缺的一部分。本博客将详细介绍一个基于Spring Boot和Vue的购物商城系统的设计与实现。该系统包含了商品展示、购物车管理、订单处理、用户管理等模块…

标签之文字排版,图片,链接,音视频(HTML) 基础版

目录 标签之文字排版,图片,链接,音视频知识点: 练习题一: 效果: 练习题二: 效果: 标签之文字排版,图片,链接,音视频知识点: 超文本:链接 标记:标签<> 双标签 单标签 <br>//换行 <hr>//水平线 向后tab 向前shifttab html注释<!----> css /**/ …