Python CV 实现风格化图片转换

news2025/1/16 7:55:19

前几天遇到一个风格化图片转换的需求,效果像这样:
在这里插入图片描述
像这样,需要用纯色圆形填充图像,形成风格化的图片样式。

实现原理

整体原理还是比较简单的,有点类似与马赛克的处理方式。
假设图片宽 w 像素,高 h 像素,需要使用半径为 r 的圆填充好,那么只需要:

  1. 先把图片划分成边长为 2*r 的栅格;
  2. 选取每个栅格中心点的像素颜色,作为这个栅格要填充的颜色;
  3. 新建画布,对每个栅格绘制实心圆形,颜色是上一步计算的结果。

代码分解

读取图片

import cv2  # pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple pip install opencv-python==4.5.5.62

img = cv2.imread(target_file)
print(f'Read image, got width={img.shape[1]}, height={img.shape[0]}')

新建画布

dest = numpy.zeros((img.shape[0], img.shape[1], 3), dtype=numpy.uint8)

这个比较简单,就是创建一个三维数组,最低维有三个元素代表颜色(BGR),第二维是行,最高维是列。

划分并遍历栅格

for i in range(0, len(img), circle_radius * 2):
    # 数组每一行代表图形中的一行,从左上角开始(i相当于y值)
    for j in range(0, len(img[i]), circle_radius * 2):
        # 数组每一列代表图形中的一列,从左上角开始(j相当于x值)
        center = (j + circle_radius, i + circle_radius)  # x, y

这里有个比较坑的点,在使用数组遍历所有像素的时候,第一层循环从从上到下遍历图片的每一行,第二层循环从左到右遍历该行的像素。
但是啊但是,CV 中的点坐标以左上角为原点,右方向为 x 轴正方向,下方向为 y 轴正方向。注意看这个 center,它的点表示要和数组访问恰好相反。

获取颜色并在新画布绘制圆形

point_color_arr = img[min(center[1], len(img)) - 1][min(center[0], len(img[i])) - 1]
point_color = (int(point_color_arr[0]), int(point_color_arr[1]), int(point_color_arr[2]))  # BGR
cv2.circle(dest, center, circle_radius, point_color, -1)

取中点处的颜色,即是我们要的颜色。注意这里访问的时候是 img[center[1]][center[0]],就是因为前面说的,点坐标与数组下标恰好相反。

优化:取栅格中全部颜色的平均值

我们还可以顺带实现一下类似于马赛克的那种,每个格子颜色取平均值,这样能使格子之间的颜色过渡更自然。

n_points = 0
point_color = [0, 0, 0]
for ii in range(i, min(i + circle_radius * 2, len(img)), 1):
    for jj in range(j, min(j + circle_radius * 2, len(img[i])), 1):
        n_points += 1
        point_color += img[ii][jj]
point_color = tuple([int(x / n_points) for x in point_color])

这里唯一要注意的点就是,直接从 img 读出来的是数组,我们需要转换成 int tuple 才能用。

写入文件或显示到屏幕

显示到屏幕可以这样:

cv2.namedWindow("image")
cv2.imshow('image', dest)
cv2.waitKey(100000)  # 显示 10000 ms 即 10s 后消失
cv2.destroyAllWindows()

要把图片保存到文件可以这样:

dest_file = 'dest-test-29-t.png'
cv2.imwrite(dest_file, dest)

完整源代码

circle_radius = 29  # in px
target_file = 'test.png'
dest_file = 'dest-test-29-t.png'
use_average = True
save_file = True

import cv2  # opencv默认读取格式是BGR
import numpy
import tqdm

# Press the green button in the gutter to run the script.
if __name__ == '__main__':
    img = cv2.imread(target_file)
    print(f'Read image, got width={img.shape[1]}, height={img.shape[0]}')

    dest = numpy.zeros((img.shape[0], img.shape[1], 3), dtype=numpy.uint8)
    for i in tqdm.tqdm(range(0, len(img), circle_radius * 2), "Processing: "):
        # 数组每一行代表图形中的一行,从左上角开始(i相当于y值)
        for j in range(0, len(img[i]), circle_radius * 2):
            # 数组每一列代表图形中的一列,从左上角开始(j相当于x值)
            center = (j + circle_radius, i + circle_radius)  # x, y
            # calculate color for this area, get average
            if use_average:
                n_points = 0
                point_color = [0, 0, 0]
                for ii in range(i, min(i + circle_radius * 2, len(img)), 1):
                    for jj in range(j, min(j + circle_radius * 2, len(img[i])), 1):
                        n_points += 1
                        point_color += img[ii][jj]
                point_color = tuple([int(x / n_points) for x in point_color])
            else:
                point_color_arr = img[min(center[1], len(img)) - 1][min(center[0], len(img[i])) - 1]
                point_color = (int(point_color_arr[0]), int(point_color_arr[1]), int(point_color_arr[2]))  # BGR
            cv2.circle(dest, center, circle_radius, point_color, -1)

    if save_file:
        cv2.imwrite(dest_file, dest)
    else:
        cv2.namedWindow("image")
        cv2.imshow('image', dest)
        cv2.waitKey(100000)  # 显示 10000 ms 即 10s 后消失
        cv2.destroyAllWindows()

程序效果

原图:
在这里插入图片描述
使用中心点作为颜色来源:
在这里插入图片描述
使用颜色平均值:
在这里插入图片描述

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

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

相关文章

FLStudio21中文版下载及水果软件2023功能介绍

如今,越来越多的音乐人选择使用音乐制作软件来进行音乐的创作,一台电脑、一款软件以及一个外接MIDI就是一个小型的音乐工作站,而如今非常流行的FL Studio(在国内被称为“水果”)成了音乐界无论萌新还是大佬们的首选&am…

二阶微分算子与反锐化屏蔽

二阶微分算子 任意二阶微分必须满足:灰度不变的区域微分值为0;灰度台阶或斜坡的起点处微分值非0;沿着斜坡的微分值为0。由于处理离散值,因此微分用差分近似: 二维图像f(x,y),沿着两个空间坐标轴求解二阶微分&#xff1…

逆向-还原代码之little-or-big (Arm 64)

// 源代码 #include <stdio.h> /* * 2016/9/29 yu liang. */ int test_one(void) { int i1; char *p(char *)&i; if(*p1) printf("Little_endian\n"); // Little_endian else printf("B…

一文弄清楚Vue中的computed与watch的区别

1.实现业务当我们点击按钮&#xff0c;就会切换h1标签的语句内容&#xff0c;再次点击按钮&#xff0c;h1标签的语句内容就会恢复&#xff0c;每次点击按钮&#xff0c;浏览器都会输出一个语句来表达监视到了h1的内容改变2.Vue中的computed计算属性2.1利用Vue中的computed计算属…

Windows server——部署DHCP服务

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 本章重点 一.DHCP概述 1.DHCP服务的好处 二.DHCP的工作原理 1.DHCP的分配方…

【云原生 | 50】Docker三剑客之Docker Compose第一节

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

pinia和vuex的区别

pinia和vuex的区别 什么是“状态管理模式”&#xff1f; const Counter {// 状态data () {return {count: 0}},// 视图template: <div>{{ count }}</div>,// 操作methods: {increment () { this.count}} }createApp(Counter).mount(#app)这个状态自管理应用包含…

字符串题记

经典字符串leetcode题 文章目录经典字符串leetcode题反转字符串第一种方法&#xff1a;使用string里的库函数reverse第二种方法&#xff1a;使用自己写的swap函数第一种swap函数第二种swap函数151.翻转字符串里的单词28. 实现 strStr()KMP算法459.重复的子字符串第一种&#xf…

UE4 后期材质节点学习

以下对应的效果&#xff1a; 材质后期在这里进行设置&#xff1a; 在这里调整场景的整体的饱和度 场景的对比度 灰度系数的调整 高光度/图像增益 灰阶偏移的设置 想了解这些专业名词可以看&#xff1a;相机gain lift gamma offset参数意义_baobei0112的博客-CSDN博客_相机gai…

Redis学习笔记(一)Linux下安装部署Redis

一、下载Redis 1、进入官网&#xff0c;进入download页面 https://redis.io/download&#xff0c;找到“List of all releases and hash digests”&#xff0c;点击“ listing of all previous Redis releases on the releases page”&#xff0c;可以进入所有版本下载页面。 …

STM32——DMA直接存储器访问

文章目录一、DMA直接存储器存取DMA简介二、存储器映像三、DMA框图四、DMA基本结构五、DMA请求&#xff08;触发源&#xff09;六、数据宽度与对齐七、存储器到存储器的DMA转运原理图关键代码八、外设到存储器的DMA转运原理图硬件链接图关键代码九、其他一、DMA直接存储器存取 …

【图像分类】4.ResNet残差模块卷积网络的神

ResNet重要性不必多说了吧&#xff0c;论文引用破10w&#xff0c;是我见过最多的&#xff0c;yyds&#xff01; 在对照博主霹雳吧啦和官方pytorch的代码下&#xff0c;手撸一个resnet。如果没有看着代码写&#xff0c;不确定自己是否能根据论文写出model&#xff0c;而且写优雅…

java学习day69(乐友商城)用户注册

今日目标&#xff1a; 创建用户中心 了解面向接口开发方式 实现数据校验功能 实现短信发送功能 实现注册功能 实现根据用户名和密码查询用户功能 1.创建用户中心 用户搜索到自己心仪的商品&#xff0c;接下来就要去购买&#xff0c;但是购买必须先登录。所以接下来我们编…

STM32MP157驱动开发——Linux IIO驱动(下)

STM32MP157驱动开发——Linux IIO驱动&#xff08;下&#xff09;0.前言一、IIO 触发缓冲区1.IIO 触发器2.申请触发器3.释放触发器4.注册触发器5.注销触发器6. IIO 缓冲区7.向驱动程序添加触发缓冲功能8.驱动编写9.触发缓冲测试10.缓冲区读取二、测试App三、测试结果0.前言 上一…

【C++高阶数据结构】B树、B+树、B*树

&#x1f3c6;个人主页&#xff1a;企鹅不叫的博客 ​ &#x1f308;专栏 C语言初阶和进阶C项目Leetcode刷题初阶数据结构与算法C初阶和进阶《深入理解计算机操作系统》《高质量C/C编程》Linux ⭐️ 博主码云gitee链接&#xff1a;代码仓库地址 ⚡若有帮助可以【关注点赞收藏】…

高等数学(第七版)同济大学 习题11-3 (前7题)个人解答

高等数学&#xff08;第七版&#xff09;同济大学 习题11-3&#xff08;前7题&#xff09; 函数作图软件&#xff1a;Mathematica 1.计算下列曲线积分&#xff0c;并验证格林公式的正确性&#xff1a;\begin{aligned}&1. \ 计算下列曲线积分&#xff0c;并验证格林公式的正…

PyTorch深度学习快速入门教程

PyTorch深度学习快速入门教程1、Pytorch加载数据2、Tensorbord的使用3、Transforms的使用4、常见的Transforms5、torchvision中的数据集使用6、DataLoader的使用7、神经网络的基本骨架—nn.module8、卷积操作9、神经网络—卷积层10、神经网络—池化层的使用11、神经网络—非线性…

靴子落地!Mobileye正式启动4D成像雷达量产进程

4D毫米波雷达赛道正在变得越来越拥挤。 在传统雷达时代&#xff0c;全球主要的市场参与者屈指可数&#xff0c;博世、大陆、安波福、海拉等少数几家巨头几乎垄断前装市场。如今&#xff0c;随着4D时代的开启&#xff0c;越来越多的新进入者希望能够实现换道超车&#xff0c;这…

Jar 组件自动化风险监测和升级实践

背景 以 Xstream、Jackson、Fasjson 等为代表的 Jar 组件高危漏洞层出不穷&#xff0c;安全组每年 N 次推动业务线进行第三方 Jar 组件升级&#xff0c;每次升级动辄涉及成百上千个应用服务&#xff0c;给双方都带来了沉重的负担。为了降低安全组在 Jar 组件升级期间的工作量&…

JS 如何利用浏览器的 cookie 保存用户名

前言 浏览器的cookie可以用来存储一些少量的网站信息,比如登录的用户名,用于提高用户体验非常有帮助 有的一些网站在第一次登录后,在指定的时间范围内容,下次在打开网站,再次登录时,不用每次都重新输入用户名的 或在做一些购物车效果时,也可以使用cookie,保持一个状态持续多…