提取图片RGB三通道数据+用RGB恢复原始图片
提取图片的RGB三通道数据+用RGB恢复原始图片
- 提取图片的RGB三通道数据
- 用RGB恢复原始图片
功能实现:
- 提取出一张图片的R、G、B三个通道的值并且将其分别转换为十进制数据存储到R.txt、G.txt、B.txt文档中
- 再将R.txt、G.txt、B.txt里的十进制数据恢复成图片形式,用以验证
代码已开源到github上
提取图片的RGB三通道数据
使用的是libjpeg库,关于如何在QT中配置libjpeg库的环境,请看我这篇博客
- 首先定义输入图片和输出文件名
char* input_filename = "C:/Users/10858/Desktop/1.jpg";char* output_filename_R = "C:/Users/10858/Desktop/output_R.txt";char* output_filename_G = "C:/Users/10858/Desktop/output_G.txt";char* output_filename_B = "C:/Users/10858/Desktop/output_B.txt";
- 打开输入文件并读取JPEG图像数据
FILE* infile = fopen(input_filename, "rb");if (!infile) {printf("无法打开文件: %s\n", input_filename);return 1;}
- 存储在内存中
fseek(infile, 0, SEEK_END); //文件指针定位到文件结尾位置size_t size = ftell(infile); //读取文件大小fseek(infile, 0, SEEK_SET); //文件指针回到文件开始位置unsigned char* jpegData = new unsigned char[size]; //在堆上分配一个内存块fread(jpegData, size, 1, infile); //数据读取到刚才分配的内存块中
- 初始化JPEG解压对象
- jpeg_decompress_struct 结构体:用来保存JPEG解压缩的相关参数
其中jpeg_mem_src()函数的作用是将大小为size的jpegData内存中的数据拷贝到cinfo.src结构体;内存的位置和大小会储存在结构体中的指针里,这样JPEG解压缩就可以直接从内存中读取JPEG图像数据进行解压缩操作了 - jpeg_error_mgr结构体:设置libjpeg解压缩时的错误处理程序
struct jpeg_decompress_struct cinfo;jpeg_create_decompress(&cinfo); //创建解压缩对象jpeg_mem_src(&cinfo, jpegData, size); //设置JPEG解压缩的源数据struct jpeg_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr);
- 读取JPEG文件头
使用libjpeg库提供的jpeg_read_header函数来读取JPEG文件头信息,该函数会解析JPEG文件头,读取其中的基本信息(包括图像的宽度、高度、压缩类型等),并将其存储在jpeg_decompress_struct结构体中
int ret = jpeg_read_header(&cinfo, TRUE);if (ret != JPEG_HEADER_OK) {fprintf(stderr, "Error: jpeg_read_header returned %d\n", ret);jpeg_destroy_decompress(&cinfo); //释放资源fclose(infile);return 1;}
- 开始解压缩JPEG文件
- 图像的像素数据的每一行的末尾会添加一些额外的字节,以确保下一行的像素数据起始地址是按照特定的字节对齐方式进行的。这个额外的字节被称为“填充字节”
- 扫描行跨度指的是一行像素数据(不包括填充字节)在内存中所占用的字节数。它通常由每行像素数和每个像素所占用的字节数计算得出,即 扫描行跨度 = 每行像素数 × 每个像素所占用的字节数
- row_pointer是一个指向buffer中当前行数据的指针。cinfo.output_scanline是 jpeg_decompress_struct 结构体中的成员变量,用于记录已经解压的扫描行数量,在处理完每一行数据后,该变量的值会自动加 1。buffer 是指向存储整个图像数据的缓冲区的指针,row 变量则表示当前正在处理的行数。因为 每个像素由 R、G、B 三个分量组成,每个分量占用一个字节,所以一行数据占用 width * 3 个字节,所以row * width * 3 就能计算出当前行的位置,而row * width * 3仅仅是当前行数据在整张图片中的起始位置,因此要加上buffer
- jpeg_read_scanlines() 函数用来扫描行数据,存储到 row_pointer 指向的内存地址中,第三个参数 1 表示每次读取一行
//开始解压缩JPEG文件jpeg_start_decompress(&cinfo);//获取图像宽度和高度int width = cinfo.output_width;int height = cinfo.output_height;//扫描行跨度:计算一行像素所需的字节数int row_stride = width * cinfo.output_components;//为解压后的图像分配内存unsigned char* buffer = new unsigned char[width * height * 3];//读取解压后的图像数据unsigned char* row_pointer;int row = 0;while (cinfo.output_scanline < height) {row_pointer = buffer + (row * width * 3);jpeg_read_scanlines(&cinfo, &row_pointer, 1);row++;}//结束解压缩JPEG文件jpeg_finish_decompress(&cinfo);
- 结束解压缩
//结束解压缩JPEG文件jpeg_finish_decompress(&cinfo);
//关闭输入文件fclose(infile);
- 将RGB格式数据存储到txt文件中
创建一个输出流对象outfile_X,后续将向该文件中写入数据。static_cast (int)用于将字节类型转换为整型
ofstream outfile_R(output_filename_R);if (!outfile_R.is_open()) {printf("无法打开文件: %s\n", output_filename_R);return 1;}ofstream outfile_G(output_filename_G);if (!outfile_G.is_open()) {printf("无法打开文件: %s\n", output_filename_G);return 1;}ofstream outfile_B(output_filename_B);if (!outfile_B.is_open()) {printf("无法打开文件: %s\n", output_filename_B);return 1;}//逐个像素地写入数据for (int i = 0; i < height; i++) {for (int j = 0; j < width; j++) {// 计算当前像素在缓冲区中的位置int pos = (i * width + j) * 3;// 将RGB三个分量的值写入txt文件中outfile_R << static_cast<int>(buffer[pos]) << endl;outfile_G << static_cast<int>(buffer[pos + 1]) << endl;outfile_B << static_cast<int>(buffer[pos + 2]) << endl;}}
- 关闭释放
outfile_R.close();outfile_G.close();outfile_B.close();
//释放内存delete[] buffer;
//清除JPEG解压缩对象jpeg_destroy_decompress(&cinfo);
输出结果:
测试图片:
用RGB恢复原始图片
为了验证R、G、B的数据是否正确,需要用这些数据恢复出原始图片
- 先要读取三个文件中的十进制数据,得到三个整数列表:r_data、g_data和b_data
with open('C:/Users/10858/Desktop/output_R.txt') as f:r_data = [int(x) for x in f.read().split()]with open('C:/Users/10858/Desktop/output_G.txt') as f:g_data = [int(x) for x in f.read().split()]with open('C:/Users/10858/Desktop/output_B.txt') as f:b_data = [int(x) for x in f.read().split()]
- 将数据填充到新建的空白图片中
# 创建空白的图片
img = Image.new('RGB', (width, height))# 填充图片
for y in range(height):for x in range(width):r = r_data[y * width + x]g = g_data[y * width + x]b = b_data[y * width + x]img.putpixel((x, y), (r, g, b))
恢复结果:
提取图片RGB三通道数据+用RGB恢复原始图片相关推荐
- 彩色图像RGB三通道问题探究
之前做图像问题研究时经常会提到RGB通道,这次做一个小研究,对最底层的东西深究一二-- 直接上全部代码吧,一点点来: # -*- coding: utf-8 -*- import cv2 img=cv ...
- BMP位图转为RGB三通道图
文章目录 读取BMP位图转为RGB三通道图 注意 相关/参考链接 本人机器开发环境 用到的图像 大小端模式介绍: 完整代码: 结果 读取BMP位图转为RGB三通道图 个人总结,目的是给自己日后参考,或 ...
- PIL将png的RGBA四通道改为jpg的RGB三通道方法
将一张png图像使用PIL读入的时候,发现是一个四通道图像,即:RGBA,分别代表Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间.其中Alpha通道一般用做透明度参数,这就是为 ...
- 【Opencv入门】RGB三通道直方图的计算与绘制
文章目录 一. 直方图概述 Overview of histogram 二.直方图的建立 Establishment of histogram 三.直方图的作用 The function of his ...
- OpenCV python 彩色图片的三通道
OpenCV python 彩色图片的三通道 #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 目的:理解彩色图片的三 ...
- MATLAB批量将单通道图片转换为三通道图片
在做深度学习训练模型时需要输入为三通道图片,当获得的数据集为单通道图片时,就需要将其转换为三通道图片. pathdir = 'E:/Image_Set/HYAL/';%文件路径 format = 'b ...
- 需要四维数据,但图片是三位数据?
需要四维数据,但图片是三位数据? 解决方法:
- 将三张灰度图转换为RGB三通道图片python
import cv2 import numpy as np from PIL import Image import matplotlib.pyplot as plt #使用cv2读取图片 img = ...
- 带alpha通道四通道的图片转成rgb三通道
查看第四通道数值范围,若最大值为255,则归一化到1,再与前三通道相乘,得到叠加透明度的结果
最新文章
- 这可能是最好的RxJava 2.x 入门教程(二)
- 利润中心与其他模块的集成
- ABAP门派现状报告
- P3935 Calculating 整除分块
- 1 MM配置-企业结构-定义-定义评估级别
- (92)如何解决信号高扇出问题,例如复位信号
- goldengate简单配置
- 【报告分享】2020情趣用品线上消费趋势报告.pdf(附下载链接)
- easyui自学模板代码
- A Game of Thrones(4)
- 2021年中国企业信息归档(EIA)市场趋势报告、技术动态创新及2027年市场预测
- 尾气冒黑烟是什么问题_汽车排气管冒黑烟,怎么回事?
- win10新建文本改html乱码,win10专业版文字乱码该怎么办?解决方法是什么?
- oTree学习教程(七)Apps rounds
- 给中国学生的第二封信:从优秀到卓越
- TI AM5728 CPSW网口调试笔记
- Ultra Light Waterproof Jacket 2014 Warm down Coats Cheap
- 拼多多校招内推编程题3 六一儿童节
- JQuery快速入门之插件
- js 伪造referer_详解php伪造Referer请求反盗链资源