学习opencv:PS滤镜—浮雕

article/2025/3/11 14:15:14

实现浮雕效果的算子有很多,效果大同小异,不同算子的处理结果在细节上会有所差异。事实上,任何一阶差分算子都可用于实现浮雕效果,简单起见,这里使用算子[-1,1]。

代码如下

#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>  using namespace std;int main()
{int rows, cols, i, j, tmp;int shift = 128, alpha = 1;cv::Mat img = cv::imread("D:\\timg.jpg");rows = img.rows;cols = img.cols;cv::Mat result(rows, cols - 1, CV_8UC3, cv::Scalar(0, 0, 0));for (i = 0; i < rows ; i++){cv::Vec3b* data1 = img.ptr<cv::Vec3b>(i);cv::Vec3b* data2 = result.ptr<cv::Vec3b>(i);for (j = 0; j < cols - 1; j++){tmp = (-data1[j][0] + data1[j + 1][0])*alpha + shift; //alpha决定雕刻"深度"data2[j][0] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;      //限制像素值范围在0~255tmp = (-data1[j][1] + data1[j + 1][1])*alpha + shift;data2[j][1] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;tmp = (-data1[j][2] + data1[j + 1][2])*alpha + shift;data2[j][2] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;}}cv::imshow("result", result);cv::waitKey(10000);return 0;
}

注意限制像素值范围很重要,否则当像素值超出范围时,int型数据赋给uchar型数据会溢出,在结果图像中会产生杂色。

效果如下

原图:

                                                                                               图1 原图

效果图:

                                                                                         图2  浮雕效果图 

上图整体呈现灰色,具有浮雕效果的立体感。边缘有略微的彩色,若要消除彩色,可将上图转为灰度图。调整代码中的alpha值,可改变雕刻"深度",增强或减弱立体感。

原理 

浮雕效果的特征是具有一定的立体感,这是通过明暗对比实现的,观察图2,可以发现一块凸起的左右边缘总有一侧比背景暗,而另一侧比背景亮,从而形成一种光线从一侧照向另一侧的视觉效果,进而形成立体感。若消除这种明暗对比,则不会形成立体感,将代码作如下修改,对差分结果取绝对值,去除明暗对比

-  tmp = (-data1[j][0] + data1[j + 1][0])*alpha + shift;
+  tmp = cv::abs(-data1[j][0] + data1[j + 1][0])*alpha + shift;-  tmp = (-data1[j][1] + data1[j + 1][1])*alpha + shift;
+  tmp = cv::abs(-data1[j][1] + data1[j + 1][1])*alpha + shift;-  tmp = (-data1[j][2] + data1[j + 1][2])*alpha + shift;
+  tmp = cv::abs(-data1[j][2] + data1[j + 1][2])*alpha + shift;

得到如下效果

                                                                                          图3  平面效果

可见,是差分算子决定了处理结果具有立体感。图像中颜色相近区域进行差分处理后,其值接近0,加上shift后像素各通道值均接近shift,因而呈现灰色,而边缘处值有较大变化,因此可能会呈现彩色,且亮度与背景不同,从而形成物体轮廓,边缘的明暗对比形成立体感,从而呈现浮雕效果。下图示意了处理过程

 

                            图4  原图                                                             图5 差分图

                                                                                          图7  结果图 

因为差分之后会存在负值,负值无法显示,因此需要一个基底衬托,一般取最大值的一半,即128,但不是绝对的。这就是图7中shift的作用,使暗边缘得以显示。

应用

图6到图7的过程可以看成是在一幅单色基底图像上叠加上差分图像,基底图像每个像素每个通道值均为shift,那么基底必须是单色图像吗,如果换成其他图像会呈现什么效果呢?下面我们尝试把一幅图像的差分图像叠加到另一幅图像上,使用图1作为基底,对图8作差分后叠加到基底上,看看会出现什么效果。

                                        

                                                                                                    图8 

代码如下

#include<iostream>  
#include <opencv2/core/core.hpp>  
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>  using namespace std;int main()
{int rows, cols, i, j, tmp;int alpha = 1;cv::Mat img1 = cv::imread("D:\\seal.jpg"); //已知seal.jpg宽高均小于timg.jpgcv::Mat img2 = cv::imread("D:\\timg.jpg"); //基底图像rows = img1.rows;cols = img1.cols;for (i = 0; i < rows ; i++){cv::Vec3b* data1 = img1.ptr<cv::Vec3b>(i);cv::Vec3b* data2 = img2.ptr<cv::Vec3b>(i);for (j = 0; j < cols - 1; j++){tmp = (-data1[j][0] + data1[j + 1][0])*alpha + data2[j][0];data2[j][0] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;tmp = (-data1[j][1] + data1[j + 1][1])*alpha + data2[j][1];data2[j][1] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;tmp = (-data1[j][2] + data1[j + 1][2])*alpha + data2[j][2];data2[j][2] = tmp < 0 ? 0 : tmp>255 ? 255 : tmp;}}cv::imshow("result", img2);cv::waitKey(100000);return 0;
}

 效果如下图所示,在图1左上角敲了个钢印。

                                                                                           图9  钢印效果 

 仔细观察可以发现,图9中的钢印中间部分不明显,这是由于只计算了x方向的差分,而印章中间部分在x方向变化小,因此差分值较小。如果叠加上y方向的差分图,就会比较明显。


http://chatgpt.dhexx.cn/article/Ly6aO7A0.shtml

相关文章

ps给图片加钢印方法

给图片加一个钢印其实很简单 这样的效果只能类似钢印 简单可以按照下面的方法 准备资料 &#xff1a;一个要加钢印的图片 一个透明印章即可实现 方法&#xff1a;斜面和浮雕 一、打开图片 二、打开透明印章 三、将透明印章移动到图片中 四、进行图层设置 右击印章图层---混合…

PS钢印效果制作

PS制作钢印效果一法 转载教程:严禁做假.... 附件 1.jpg (37.05 KB) 2008-6-10 22:39 2.jpg (33.59 KB) 2008-6-10 22:39 3.jpg (38.57 KB) 2008-6-10 22:39 4.jpg (42.49 KB) 2008-6-10 22:39 5.jpg (39.2 KB) 2008-6-10 22:39 6.jpg (44.63 KB) 2008-6-10 22:39 7.jpg…

Oracle中extract()函数

oracle中extract()函数从oracle 9i中引入的,主要作用于一个date或者interval类型中截取特定的部分 extract()语法如下&#xff1a; extract ( { year | month | day | hour | minute | second | 某一时区 } from { date类型值 | interval类型值} ) 要点一&#xff1a;extract()…

oracle ora-01652:无法通过1024(在表空间SYSTEM中)拓展temp段

1.报错 2.查询拓展表空间 2.1查看表空间使用情况 SELECT UPPER(F.TABLESPACE_NAME) "表空间名",D.TOT_GROOTTE_MB "表空间大小(M)",D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.…

hpux oracle10.2.0.4下报ORA-1652 unable to extend temp segment by 128 in tablespace CARDTS

hpux oracle10.2.0.4 rac 下报ORA-1652 unable to extend temp segment by 128 in tablespace CARDTS hpux 11.31 oracle10.2.0.4 rac ,2 nodes 值得注意的是&#xff0c;报的是不能在CARDTS表空间中扩展temp段。。。 后来查询metalink 文章&#xff0c; Troubleshooting ORA-1…

原创:oracle中单行函数介绍 lt;五gt;

在SQL中有两种函数一种是单行函数&#xff0c;一种是多行函数.在sql与pl/sql中都自带了很多类型的函数,比如有字符、数字、日期、转换和混合型等多种函数用于处理单行数据,因此这些都被称为单行函数.这些函数都可以被用于select、where和oder by等子句中.下面我们就来分析单行函…

EXPDP报错:ORA-60019 creating initial extent of size 14 in tablespace of extent size 8

一、原因概述 和SecureFiles新的LOB架构相关。11g之前叫BasicFiles。在11g如果不特别指定&#xff0c;默认是会创建成BasicFiles LOB。但是在12c之后&#xff0c;LOB列在ASSM管理的表空间。默认都会创建成SecureFiles。 也就是DB_SECUREFILE初始化参数&#xff0c;在11g时&…

oracle 中 /*+ full(表名)*/ 优化详解

文章目录 hint 关键字&#xff1a; /* full(表名)*/可能遇到的问题别名为 "SELxx" hint 关键字&#xff1a; / full(表名)/ 一般来说&#xff0c;sql 优化时&#xff0c;尽量走 index&#xff0c;但不绝对有时候&#xff0c;全表扫描的效率比索引高 索引 和 全表扫…

Docker——Docker 镜像详解

Docker 镜像 Docker镜像是什么Docker镜像加载原理联合文件系统&#xff08;UnionFS&#xff09;镜像加载原理镜像分成理解 Commit镜像镜像的总结 Docker镜像是什么 Docker 容器的运行是基于宿主机的内核&#xff0c;通过linux的namespaces来实现隔离&#xff0c;相对于虚拟机而…

Docker镜像使用详解

目录 基础命令使用进阶 容器和虚拟机具有相似的资源隔离和分配优势&#xff0c;但功能不同&#xff0c;因为容器虚拟化的是操作系统而不是硬件。多个容器可以在同一台机器上运行&#xff0c;并与其他容器共享操作系统内核&#xff0c;每个容器在用户空间中作为独立进程运行。一…

docker镜像下载及docker镜像管理

文章目录 docker镜像下载镜像说明通外网主机上获取镜像官网上查看镜像的详细说明 镜像的命名方式镜像的重命名镜像的删除删除单个删除全部镜像 镜像的打包与解压包默认存放路径说明镜像打包【单个】镜像打包【多个】镜像解压 容器的导出和导入把容器导出为镜像镜像导入为容器 查…

Docker基础 - 仓库,镜像,容器详解

仓库&#xff0c;镜像&#xff0c;容器的关系 我们再回顾下仓库&#xff0c;镜像&#xff0c;容器的关系&#xff08;这是官网的图&#xff09; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NBtYxRyR-1683856218077)(null)] Docker 镜像 当运行…

Docker本地镜像推送到私有库

Docker Registry是官方提供的工具&#xff0c;可以用于构建私有镜像仓库 1. 下载镜像Docker Registry docker pull registy 2. 运行私有库Registry&#xff0c;相当于本地有个私有Docker hub docker run -d -p 5000:5000 -v /zzyyuse/myregistry/:/tmp/registry --privileg…

docker镜像

docker镜像 文章目录 docker镜像1.镜像的概念2.docker镜像层3.docker存储驱动3.docker registry4.Docker Hub 1.镜像的概念 Docker镜像类似于虚拟机中的镜像&#xff0c;是一个只读的模板&#xff0c;也是一个独立的文件系统&#xff0c;包括运行容器所需的数据。 Docker镜像…

Docker入门教程:本地打包docker镜像

什么是Docker&#xff1f; Dockers是基于Go语言开发的虚拟容器技术。以前我们部署应用通常是将源代码打包成一个jar包运行&#xff0c;这样就会受到运行环境、配置环境的限制&#xff0c;而且程序也不能跨服务器运行。Docker基于Linux容器技术&#xff0c;将Java源代码、运行环…

Docker 镜像

&#xff08;一&#xff09;下载实例 &#xff08;二&#xff09;镜像基本操作 备注&#xff1a; 相同名称的镜像可以存在多个&#xff0c;即需要不同的tags版本 &#xff08;三&#xff09;使用 Dockerfile 定制镜像 &#xff08;1&#xff09;介绍 镜像的定制实际上就是定…

Docker (一)之docker镜像库地址

一、关于docker的镜像问题&#xff1a; 当我们想要去拉取一个镜像的时候&#xff0c;初始的时候会去从国外的镜像库里面拉取&#xff0c;速度可想而知&#xff1b;这时我们需要给docker配置一个国内的镜像库&#xff1a; 目前发现docker有2个地方可以配置镜像库的地址&#x…

Docker镜像发布到阿里云和私有库

目录 一、Docker镜像 &#xff08;一&#xff09;概述 &#xff08;二&#xff09;Docker镜像加载原理 &#xff08;三&#xff09;镜像分层结构优势 &#xff08;四&#xff09;重点理解 &#xff08;五&#xff09;docker commit操作实例 &#xff08;六&#xff09;总…

【云原生|Docker】Docker镜像操作

作者&#xff1a;柒号华仔 个人主页&#xff1a;欢迎访问我的主页 个人信条&#xff1a;星光不问赶路人,岁月不负有心人。 个人方向&#xff1a;主要方向为5G&#xff0c;同时兼顾其他网络协议&#xff0c;编解码协议&#xff0c;C/C&#xff0c;linux&#xff0c;云原生等&…

Docker私有镜像仓库是什么?

Docker镜像仓库概述 镜像仓库作为Docker技术的核心组件之一&#xff0c;其主要作用就是负责镜像内容的存储和分发。Docker镜像仓库从使用范围来说分为“公有镜像仓库”和“私有镜像仓库”&#xff0c;公有镜像仓库是可以被任何人使用的&#xff0c;例如Docker公司维护的在线存储…