如果需要处理的原图及代码,请移步小编的GitHub地址

  传送门:请点击我

  如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice

  本来不想碎碎念,但是我已经在图像后缀上栽倒两次了。而且因为无意犯错,根本找不到问题。不论是在深度学习的语义分割中,还是在图像处理的软件(Halcon, Cognex)中都载过跟头,于是痛定思痛,决定将自己的经验写进这篇博客中,如果看到这篇的看官,希望不要再犯了。

问题1:乱修改图像后缀名称,部分软件会报错(halcon error #5580:PNG:file is not a PNG file)

  首先是下面的报错,因为openCV使用多了,我们经常会通过cv2.imread()加载出三通道的图像,所以默认图像都是BGR的,无论图像是png, bmp 还是 jpg。反正都可以读出三通道的,即使有时候无意将图像后缀命名为png或者jpg(或者我们网上下载的数据集中被修改了后缀),我们都不在意。但是实际上部分软件不会像opencv自动处理,我在这里就报错了。

OpenCV计算机视觉学习(14)——浅谈常见图像后缀(png, jpg, bmp)的区别(opencv读取语义分割mask的坑)-LMLPHP

  具体深入下去,就是下图,实际上图像后缀是jpg,但是我拿到的数据是png,而我直接喂入软件就报错如上:

OpenCV计算机视觉学习(14)——浅谈常见图像后缀(png, jpg, bmp)的区别(opencv读取语义分割mask的坑)-LMLPHP

   实际上这两个图像都是png图像,但是可能就会出现有些人误命名,将其图像后缀命名为jpg。这就导致了上面的问题。

  我们具体分析,当我们将图像后缀从.png修改为.jpg时,实际上并没有改变图像的编码方式和文件结构。而如我上面所说,OpenCV是一个功能强大的计算机视觉库,它可以根据文件的实际内容来识别图像格式,而不仅仅依赖于文件后缀。因此,OpenCV能够读取被错误命名的图像文件。

  然而,其他一些软件可能只依赖于文件后缀来确定图像格式,而不会尝试解析文件内容。当你将图像后缀从.png修改为.jpg时,这些软件可能会尝试按照JPEG格式去解析该文件,但是由于文件实际上是一个PNG格式的图像,所以会报错并指出文件不是一个有效的PNG文件。

  所以要正确地处理图像文件,建议使用正确的文件后缀来反映实际的图像格式。这样可以确保不同的软件能够正确地解析和处理图像文件。

问题2:图像随便保存为jpg,结果mask结果对不上

  当我写这篇博客的时候,我发现也有网友有同样的问题,哈哈哈,于是我就更坚决了自己要写这个的原因。

  首先复现一下下面问题,并解释一下。

OpenCV计算机视觉学习(14)——浅谈常见图像后缀(png, jpg, bmp)的区别(opencv读取语义分割mask的坑)-LMLPHP

  我们就将输出的图像保存为图像(即jpg和png),然后读取出来,看看结果:

import sys
import os
import numpy as np


def count_pixel_values(image):
    count_res = {}
    # 统计像素值数量
    pixel_counts = np.bincount(image.flatten())
    # 显示结果
    for pixel_value, count in enumerate(pixel_counts):
        if count > 0:
            count_res[pixel_value] = count
    return count_res


# 读取一张图像,将其转换为灰度图
image = cv2.imread(r"./Abyssinian_1.png", 0)

# 创建二值图像
binary_image = np.zeros_like(image, dtype=np.uint8)
binary_image[image == 1] = 0  # 像素值1对应0像素
binary_image[image == 2] = 125  # 像素值2对应125像素
binary_image[image == 3] = 255  # 像素值3对应255像素

# 1, 我将二值图结果保存为jpg 和png,我们分别看看
# cv2.imwrite(r"./cat.png", binary_image)
# cv2.imwrite(r"./cat.jpg", binary_image)

# 2, 我分别打开png 和 jpg 的图像

png_mask = cv2.imread(r"./cat.png", 0)
jpg_mask = cv2.imread(r"./cat.jpg", 0)
print(np.array_equal(png_mask, binary_image), np.sum(png_mask != binary_image))
pixel_counts_png = count_pixel_values(png_mask)
print(pixel_counts_png)
print(np.array_equal(jpg_mask, binary_image), np.sum(jpg_mask != binary_image))
pixel_counts_jpg = count_pixel_values(jpg_mask)
print(pixel_counts_jpg)

# 使用sys.getsizeof()函数来获取图像对象的大小
# 使用os.path.getsize()函数来获取图像文件的大小
binary_image_memory_size = sys.getsizeof(binary_image)
png_mask_memory_size = sys.getsizeof(png_mask)
jpg_mask_memory_size = sys.getsizeof(jpg_mask)
print("二值图图像内存大小: {} 字节".format(binary_image_memory_size))
print("jpg二值图图像内存大小: {} 字节".format(png_mask_memory_size))
print("png二值图图像内存大小: {} 字节".format(jpg_mask_memory_size))
binary_image_file_size = os.path.getsize(r"./Abyssinian_1.png")
png_mask_file_size = os.path.getsize(r"./cat.png")
jpg_mask_file_size = os.path.getsize(r"./cat.jpg")
print("二值图图像文件大小: {} 字节".format(binary_image_file_size))
print("jpg二值图图像文件大小: {} 字节".format(png_mask_file_size))
print("png二值图图像文件大小: {} 字节".format(jpg_mask_file_size))

"""
True 0
{0: 22938, 125: 198766, 255: 18296}
False 8258
{0: 21455, 1: 701, 2: 414, 3: 234, 4: 95, 5: 27, 6: 7, 7: 4, 8: 1, 119: 2, 120: 27, 121: 147, 122: 259, 123: 517, 124: 839, 125: 195208, 126: 879, 127: 449, 128: 258, 129: 123, 130: 38, 131: 17, 132: 3, 248: 7, 249: 12, 250: 71, 251: 170, 252: 421, 253: 911, 254: 1625, 255: 15079}


"""
07-17 11:34