图片处理OpenCV IMDecode模式说明【生产问题处理】

OpenCV IMDecode模式说明【生产问题处理】

1 前言

今天售后同事反馈说客户使用我们的图片处理,将PNG图片处理为JPG图片之后,变为了白板。

  • 我们图片处理使用的是openCV来进行处理

2 分析

2.1 图片是否损坏:非标准PNG头部

于是,马上写了一个demo尝试本地复现,结果复现概率是:必现。

package mainimport ("fmt""gocv.io/x/gocv"_ "image/jpeg"_ "image/png""io""os"
)func main() {params := []int{gocv.IMWriteJpegQuality, 1}srcFile, err := os.Open("/Users/xxx/GolandProjects/xxx/image-encoder/demo/quality/3.png")if err != nil {fmt.Printf("%v", err)return}defer srcFile.Close()imageBuf, err := io.ReadAll(srcFile)if err != nil {fmt.Printf("%v", err)return}mat, err := gocv.IMDecode(imageBuf, gocv.IMReadUnchanged)if err != nil {fmt.Printf("%v", err)return}buf, err := gocv.IMEncodeWithParams(gocv.JPEGFileExt, mat, params)//buf, err := gocv.IMEncodeWithParams(gocv.JPEGFileExt, mat, params)if err != nil {fmt.Printf("%v", err)return}os.WriteFile("/Users/xxx/GolandProjects/xxx/image-encoder/demo/quality/33.jpg", buf.GetBytes(), os.ModePerm)if err != nil {fmt.Printf("%v", err)return}println("DONE.....")
}

接着尝试将我本地其他的PNG图片转换为JPG,发现可以转换成功。表示这个代码是可以将PNG转换为JPG的。

于是,开始排查是否是客户图片有破损,比如图片的文件头已经损坏,导致它不是一个标准的PNG图片。

在这里插入图片描述

通过查阅资料后发现PNG的头部为89 50 4E 47 0D 0A 1A 0A
在这里插入图片描述

package mainimport ("encoding/hex""fmt""os"
)func main() {filePath := "/Users/xsky/GolandProjects/xxx/image-encoder/demo/quality/11.png" // 替换为你的 PNG 图片文件路径file, err := os.Open(filePath)if err != nil {fmt.Println("Error opening file:", err)return}defer file.Close()header := make([]byte, 8)_, err = file.Read(header)if err != nil {fmt.Println("Error reading file:", err)return}fmt.Println("PNG 文件头的16进制信息:")//89504e470d0a1a0a//89504e470d0a1a0afmt.Println(hex.EncodeToString(header))
}

最终验证发现,客户的PNG图片与我本地PNG图片一致,文件头都是符合PNG格式的。

2.2 Alpha图像通道问题(shooting)

接着想着客户图像是灰白色的,而我之前验证的本地图片为彩色,加上我自己gocv处理图片的参数选择的是gocv.IMReadUnchanged。点进去查看源码,发现还有其他的参数,于是尝试替换其他参数。

//我之前代码的用法
mat, err := gocv.IMDecode(imageBuf, gocv.IMReadUnchanged)
// IMReadUnchanged return the loaded image as is (with alpha channel,
//otherwise it gets cropped).
IMReadUnchanged IMReadFlag = -1 # 处理带有Alpha参数的图像
// IMReadColor always converts image to the 3 channel BGR color image.
IMReadColor IMReadFlag = 1 # 将图片转换为BGR三色通道
// IMReadAnyColor the image is read in any possible color format.
IMReadAnyColor IMReadFlag = 4 # 根据图像自动识别任何可能的格式
...

知道这个参数之后,我将gocv.IMDecode(imageBuf, gocv.IMReadUnchanged)中的IMReadUnchanged改为IMReadAnyColor,最后验证,成功处理客户图片。

目前可以知道,我的图像处理参数选择有问题。于是开始查这几种参数有什么区别。其实点进去看源码就可以知道这几种参数的区别。

这个时候如果对图像处理不熟悉的朋友可能会问,Alpha通道是什么意思,其实大家可以简单的理解为和图像的透明度有关。

为了验证这个结论是否正确,我尝试读取客户的PNG和我本地的彩色PNG的颜色Model是否不同:

//color.RGBAModel # 我自己的图像
//color.Gray16Model # 客户的图像

至此,猜想成立,可以知道是我图像的处理颜色的参数选择有误。

3 拓展:图像color.Model

色彩模型(RGB,RGBA,CMYK灰度)
matplotlib中的色彩定义主要用到了RGB、RGBA、CMYK、灰色四种模型。

  • 这里我主要介绍RGBA模型

对这块感兴趣的朋友可以去看这边文章:https://blog.csdn.net/mighty13/article/details/113616772

3.1 color.RGBAModel:三色+Alpha

带有alpha[RGBA 表示传统的32位预处理 Alpha 色,每个颜色都有8位,分别表示红色,绿色,蓝色和阿尔法。 ]

type RGBA struct {R, G, B, A uint8
}

3.2 color.RGBA64Model:64位表示三色+Alpha的值

带有alpha:64位数来表示每个通道的值

type RGBA64 struct {R, G, B, A uint16
}

3.3 color.NRGBAModel:其他颜色不预乘Alpha的值

NRGBA 表示非 Alpha 预乘32位颜色(非 alpha 预乘表示在进行颜色合成时,颜色值不会提前乘以 alpha 通道的值)

  • 预乘:什么是预乘?假设一个像素点,用RGBA四个分量来表示,记做(R,G,B,A),那预乘后的像素就是(RA,GA,B*A, A),这里A的取值范围是[0,1]。所以,预乘就是每个颜色分量都与该像素的alpha分量预先相乘。可以发现,对于一个没有透明度,或者说透明度为1的像素来说,预乘不预乘结果都是一样的。
  • NRGBA代表一个没有32位透明度加乘的颜色。每个红,绿,蓝和透明度都是8bit的数值
type NRGBA struct {R, G, B, A uint8
}

3.4 color.NRGBA64:非预乘Alpha,其他颜色用64位表示

NRGBA64 表示非 alpha 预乘 64 位颜色,每个红色,绿色,蓝色和 alpha 有 16 位

  • NRGBA64代表无透明度加乘的64-bit的颜色,它的每个红,绿,蓝,和透明度都是个16bit的数值。
type NRGBA struct {R, G, B, A uint16
}

3.5 color.AlphaModel:代表一个8-bit的透明度

type Alpha struct {A uint8
}

3.6 color.Alpha16Model:代表一个16位的透明度

type Alpha struct {A uint16
}

3.7 color.GrayModel:灰度通道,黑白图像

只有一个灰度通道,通常用于表示黑白图像【当你需要读取只带有灰度通道的图像时,你应该使用该标志来读取图像。】【也是由RGB组成,不过由于是单通道,因此呈现灰度】

3.8 color.Gray16Model:16位整数表示灰度通道值

16位整数表示灰度通道的值,通常用于表示黑白

参考:

  • https://blog.csdn.net/zxcasd11/article/details/109446056
  • https://blog.csdn.net/u013943420/article/details/76855416

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

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

相关文章

SHAP(六):使用 XGBoost 和 HyperOpt 进行信用卡欺诈检测

SHAP(六):使用 XGBoost 和 HyperOpt 进行信用卡欺诈检测 本笔记本介绍了 XGBoost Classifier 在金融行业中的实现,特别是在信用卡欺诈检测方面。 构建 XGBoost 分类器后,它将使用 HyperOpt 库(sklearn 的 …

【U8+】用友U8删除固定资产卡片,提示:当前卡片不是本月录入的卡片,不能删除。

【问题描述】 用友U8软件,参照已有账套新建账套的时候,选择结转期初余额。 例如:参照已有账套的2022年新建2023年的账套。 结转期初的时候勾选了固定资产模块, 建立成功后登录23年新的账套后,删除固定资产卡片&#xf…

基于Eclipse+SDK+ADT+DDMS的安卓开发环境完整搭建过程

基于EclipseSDKADTDDMS的安卓开发环境完整搭建过程 1 基本概念2 SDK安装3 Eclipse安装4 ADT插件安装4.1 在线安装(太慢不建议选择)4.2 离线安装(建议选择) 5 配置SDK6 集成安装7 创建安卓虚拟设备8 创建并启动安卓虚拟机8 关于DDM…

nextjs入门

创建项目 npx create-next-app 项目名 体验文件路由 nextjs提供了文件路由的功能, 根据文件系统的目录结构, 可以识别为对应的页面路由 创建页面 首先, 在src下创建pages目录, 然后创建一个about文件(对应about页面)和main/index.js文件(对应首页) pages/main/index con…

c语言:整数与浮点数在内存中的存储方式

整数在内存中的存储: 在计算机内存中,整数通常以二进制形式存储。计算机使用一定数量的比特(bit)来表示整数,比如32位或64位。在存储整数时,计算机使用补码形式来表示负数,而使用原码形式来表示…

【计算机网络学习之路】URL概念及组成

目录 一. URL是什么 二. URL的组成 三. encode和decode 前言 本系列文章是计算机网络学习的笔记,欢迎大佬们阅读,纠错,分享相关知识。希望可以与你共同进步。 本篇讲解使用浏览器不可或缺的部分——URL 一. URL是什么 域名及DNS 我们在…

43 - 什么是数据的强、弱一致性?

说到一致性,其实在系统的很多地方都存在数据一致性的相关问题。除了在并发编程中保证共享变量数据的一致性之外,还有数据库的 ACID 中的 C(Consistency 一致性)、分布式系统的 CAP 理论中的 C(Consistency 一致性&…

Android studio Load error:undefined path variables

android stuido 报错 Load error:undefined path variables Gson is undefined 处理方法: 点击进行Sync Project with Gradle Files

Redis——某马点评day02——商铺缓存

什么是缓存 添加Redis缓存 添加商铺缓存 Controller层中 /*** 根据id查询商铺信息* param id 商铺id* return 商铺详情数据*/GetMapping("/{id}")public Result queryShopById(PathVariable("id") Long id) {return shopService.queryById(id);} Service…

文心版吴恩达课程:语义核心(Semantic Kernel)插件的商业应用

文心版吴恩达课程:语义核心(Semantic Kernel)插件的商业应用 Semantic Kernel is an SDK that integrates Large Language Models (LLMs) like OpenAI, Azure OpenAI, and Hugging Face with conventional programming languages like C#, P…

leetcode:225. 用队列实现栈

一、题目 链接:225. 用队列实现栈 - 力扣(LeetCode) 函数原型: typedef struct { } MyStack; MyStack* myStackCreate() void myStackPush(MyStack* obj, int x) int myStackPop(MyStack* obj) int myStackTop(MyStack* obj) …

代码随想录刷题题Day4

刷题的第四天,希望自己能够不断坚持下去,迎来蜕变。😀😀😀 刷题语言:C / Python Day4 任务 ● 24. 两两交换链表中的节点 ● 19.删除链表的倒数第N个节点 ● 面试题 02.07. 链表相交 ● 142.环形链表II 1 …

大数据技术之Flume(超级详细)

大数据技术之Flume(超级详细) 第1章 概述 1.1 Flume定义 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume基于流式架构,灵活简单。 1.2 Flume组成架构 Flume组成架构如…

react-route-dom 实现简单的嵌套路由

最终效果 点击 to test1 点击to test2 > to test21 点击to test2 > to test22 代码如下 path: "page",element: <父组件 />,children: [{ path: "test1", element: <Test1 /> },{path: "test2",element: <Test2 />…

Springboot自定义starter

一、start背景和简介 1.背景 工作中经常需要将多个springboot项目共同的非业务模块抽取出来&#xff0c;比如访问日志、维护请求上下文中的用户信息或者链路id等等。此次模拟的是请求中用户信息维护&#xff0c;方便整个请求中用户信息的取用。 2.作用 根据项目组的实际需求…

【WPF.NET开发】创建简单WPF应用

本文内容 先决条件什么是 WPF&#xff1f;配置 IDE创建项目设计用户界面 (UI)调试并测试应用程序 通过本文你将熟悉在使用 Visual Studio 开发应用程序时可使用的许多工具、对话框和设计器。 你将创建“Hello, World”应用程序、设计 UI、添加代码并调试错误。在此期间&#…

策略设计模式

package com.jmj.pattern.strategy;public interface Strategy {void show(); }package com.jmj.pattern.strategy;public class StrategyA implements Strategy{Overridepublic void show() {System.out.println("买一送一");} }package com.jmj.pattern.strategy;p…

Raft 算法

Raft 算法 1 背景 当今的数据中心和应用程序在高度动态的环境中运行&#xff0c;为了应对高度动态的环境&#xff0c;它们通过额外的服务器进行横向扩展&#xff0c;并且根据需求进行扩展和收缩。同时&#xff0c;服务器和网络故障也很常见。 因此&#xff0c;系统必须在正常…

组件化编程

hello&#xff0c;我是小索奇&#xff0c;精心制作的Vue系列持续发放&#xff0c;涵盖大量的经验和示例&#xff0c;如果对您有用&#xff0c;可以点赞收藏哈~ 组件化编程 组件是什么&#xff1f; 一句话概括就是&#xff1a;实现特定功能的模块化代码单元 vm就是大哥&#xff…

flink源码分析之功能组件(四)-slot管理组件II

简介 本系列是flink源码分析的第二个系列&#xff0c;上一个《flink源码分析之集群与资源》分析集群与资源&#xff0c;本系列分析功能组件&#xff0c;kubeclient&#xff0c;rpc&#xff0c;心跳&#xff0c;高可用&#xff0c;slotpool&#xff0c;rest&#xff0c;metrics&…