精华内容
下载资源
问答
  • 数字图像处理(一)——BMP图像的介绍和读取

    千次阅读 多人点赞 2020-03-03 10:34:35
    C(C++)语言实现BMP图像的读取,BMP图像的读取,BMP图像的介绍,数字图像处理,C(C++)语言读取BMP图像的像素值。

      数字图像处理的代码在网上已经非常普遍了,但是大部分文章中的代码都是针对某一个功能的,而且实现功能的编程语言种类非常多,这在小贾学习的过程中造成了很多的麻烦。所以小贾打算写几篇的文章来总结小贾在入门时候遇到的“坑”。如果您只想参考图像处理过程中的代码,您可以直接跳到文章的代码部分。小贾在代码中也会有代码的详细注释。当然,如果您刚刚入坑,小贾也会在文章中附加一些段落来帮你理解图像处理。

    1. 写在前面

    1.1. 先放一张图

    Lena.bmp
      熟悉图像处理的人一定认识这张图像。因为他们在实验或者项目任务中经常使用Lena图像。Lena图像已经成为被广泛使用的测试图像。今天,Lena图像的使用被认为是数字图像历史上最重要的事件之一1。如果你刚开始接触图像处理,那么恭喜你以后要经常见到这个图像了。

    1.2. 再说一种图像格式

      说完了上面的图片,那么接下来再了解一种图像格式:BMP。
      BMP是英文Bitmap(位图)的缩写,它是Windows操作系统中的标准图像文件格式2,其能够被多种Windows应用程序所支持。这种格式的特点是包含的图像信息比较丰富,几乎不进行压缩,但由此导致了它与生俱来的缺点——占用空间过大。

    1.3. 接着介绍一个头文件

      随着Windows的逐渐普及,支持BMP图像格式的应用软件越来越多。这主要是因为Windows把BMP作为图像的标准格式,并且内含了一套支持BMP图像处理的API函数。在C(C++)语言编程中,这套API函数的存在是以Windows.h头文件存在于系统中。在用C(C++)语言3编程实现图像处理的时候我们我们需要在代码最前端引用Windows.h头文件。
      Windows.h头文件中包含了windef.h、winnt.h、winbase.h、winuser.h、wingdi.h等头文件,涉及到了Windows内核API,图形界面接口,图形设备函数等重要的功能。

    2. BMP文件格式

      BMP文件格式4可分为文件信息头、位图信息和位图数据三部分。

    2.1. 文件信息头

      BMP文件头含有BMP文件的类型、大小和存放位置等信息。Windows.h中对其定义为:

    typedef struct tagBITMAPFILEHEADER{
    	WORD bftype; // 位图文件的类型,必须设置为BM
    	DWORD bfSize; // 位图文件的大小,以字节为单位
    	WORD bfReserved1; // 位图文件保留字,必须设置为0
    	WORD bfReserved2; // 位图文件保留字,必须设置为0
    	DWORD bfoffBits; // 位图数据相对于位图文件头的偏移量表示
    } BITMAPFILEHEADER;
    
    2.2. 位图信息

      位图信息用BITMAPINFO结构定义,它是由位图信息头(bitmap-information header)和彩色表(color table)组成,位图信息头用BITMAPINFOHEADER结构定义,彩色表用RGBQUAD结构定义。BITMAPINFO结构具有如下形式:

    typedef struct tagBITMAPINFO{
    	BITMAPINFOHEADER bmiHeader;
    	RGBQUAD bmiColor[];
    } BITMAPINFO;
    

      (1)bmiHeader是一个位图信息头(BITMAPINFOHEADER)类型的数据类型,用于说明位图的尺寸。BITMAPINFOHEADER的定义如下:

    typedef struct tagBITMAPINFOHEADER{
    	DWORD biSize; // bmiHeader结构的高度
    	DWORD biWidth; // 位图的宽度,以像素为单位
    	DWORD biHeight; // 位图的高度,以像素为单位
    	WORD biPlanes; // 目标设备的位平面数,必须为1
    	WORD biBitCount; // 每个像素的位数,必须是1(单色)、4(16色)、8(256色)或24(真彩色)
    	DWORD biCompression; // 位图的压缩类型,必须是0(不压缩)、1(BI-RLE8压缩类型)或2(BI-RLE4压缩类型)
    	DWORD biSizeImage; // 位图的大小,以字节为单位
    	DWORD biXPeIsPerMeter; // 位图的目标设备水平分辨率,以每米像素数为单位
    	DWORD biYPeIsPerMeter; // 位图的目标设备垂直分辨率,以每米像素数为单位
    	DWORD biClrUsed; // 位图实际使用的颜色表中的颜色变址数
    	DWORD biClrImpotant; // 位图显示过程中被认为重要颜色的变址数
    } BITMAPINFOHEADER;
    

      (2)bmiColor[ ]是一个颜色表,用于说明位图中的颜色。它有若干个表项,每一表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD的定义如下:

    typedef tagRGBQUAD{
    	BYTE rgbBlue;
    	BYTE rgbGreen;
    	BYTE rgbRed;
    	BYTE rgbReserved;
    } RGBQUAD;
    

      在RGBQUAD定义的颜色中,蓝色的亮度由rgbBlue确定,绿色的亮度由rgbGreen确定,红色的亮度由rgbRed确定。rgbReserved必须为0。
      例如:若某表项为00,00,FF,00,那么它定义的颜色为存红色。
      bmiColor[ ]表项的个数由biBiCount来定:
      当 biBitCount = 1、4、8 时,bmiColor[ ]分别有 2,16,256 个表项。若某点的像素值为 n,则该像素的颜色为bmiColor[n]所定义的颜色。
      当 biBitCount = 24 时,bmiColor[ ]的表项为空。位图阵列的每 3 个字节代表一个像素,3 个字节直接定义了像素颜色中蓝、绿、红的相对亮度,因此省去了bmiColor[ ]颜色。

    2.3. 位图数据

      位图阵列记录了位图的每一个像素值。在生成位图文件时,Windows从位图的左下角开始(即从左到右从下到上)逐行扫描位图,将位图的像素值一一记录下来。这些记录像素值的字节组成了位图阵列。位图阵列有压缩和非压缩两种存储格式。
      (1)非压缩格式。在非压缩格式中,位图的每个像素值对应位图阵列的若干位(bits),位图阵列的大小由位图的亮度、高度及位图的颜色数决定。
       a.位图扫描行与位图阵列的关系
      设记录一个扫描行的像素值需 n 个字节,则位图阵列的 0 至 n-1 个字节记录了位图的第一个扫描行的像素值;位图阵列的 n 至 2n-1 个字节记录了位图的第二个扫描行的像素值;依此类推,位图排列的 (m-1) x n 至 m x n - 1 个字节记录了位图的第 m 个扫描行的像素值。位图阵列的大小为 n * biHeight。
      当 (biWidth * biBitCount) mod32 = 0 时,n = (biWidth * biBitCount) / 8
      当 (biWidth * biBitCount) mod32 ≠ 0 时,n = (biWidth * biBitCount) / 8 + 4
      上式中 +4 而不是 +1 的原因是为了使一个扫描行的像素值占用位图阵列的字节数为 4 的倍数(Windows规定其必须在long边界结束),不足的位用 0 补充。
       b.位图像素值与位图阵列的关系(以第 m 扫描行为例)
      设记录第 m 个扫描行的像素值的 n 个字节分别为a0,a1,a2,···,则
      当 biBitCount = 1 时:a0 的 D7 记录了位图的第 m 个扫描的第 1 个像素值,D6位记录了位图的第 m 个扫描行的第 2 个像素值,···,D0 记录了位图的第 m 个扫描行的第 8 个像素值,a1 的 D7 位记录了位图的第 m 个扫描行的第 9 个像素值,D6 位记录了位图的第 m 个扫描行的第 10 个像素值··· ···
      当 biBitCount = 4 时:a0 的 D7 ~ D4 位记录了位图的第 m 个扫描行的第 1 个像素值,D3 ~ D0 位记录了位图的第 m 个扫描行的第 2 个像素值,a1 的 D7 ~ D4 位记录了位图的第 m 个扫描行的第 3 个像素值··· ···
      当 biBitCount = 8 时:a0 记录了位图的第 m 个扫描行的第 1 个像素值,a1 记录了位图的第 m 个扫描行的第 2 个像素值··· ···
      当 biBitCount = 24 时:a0、a1、a2 记录了位图的第 m 个扫描行的第 1 个像素值,a3、a4、a5 记录了位图的第 m 个扫描行的第 2 个像素值··· ···
      位图其他扫描行的像素值与位图阵列的对应关系与此相似。
      (2)压缩格式。Windows支持 BI_RLE8 及 BI_RLE4 压缩位图存储格式,压缩减少了位图阵列所占用的磁盘空间。
       a. BI_RLE8 压缩格式
      当biCompression = 1 时,位图文件采用此压缩编码格式。压缩编码以两个字节为基本单位。其中第一个字节规定了用两个字节所指定的颜色出现的连续像素的个数。
      例如,压缩编码 05 04 表示从当前位置开始连续显示 5 个像素,着 5 个像素的像素值均为 04。
      在第一个字节为零时,第二个字节有特殊的含义:0——行末;1——图末;2——转义后面的两个字节,这两个字节分别表示一个像素从当前位置开始的水平位移和垂直位移;n (0x003 < n < 0xFF)——转义后面的 n 个字节,其后的 n 像素分别用这 n 个字节所指定的颜色画出。注意:实际编码时必须保证后面的字节数是 4 的倍数,不足的位用 0 补充。
       b. BI_RLE4 压缩格式
      当 biCompression = 2时,位图文件采用此种压缩编码格式。它与 BI_RLE8 的编码方式类似,唯一的不同是:BI_RLE4 的一个字节包含了两个像素的颜色。当连续显示时,第一个像素按字节高四位规定的颜色画出··· ···直到所有像素都画出为止。
      归纳起来,BMP图像文件有下列四个特点:
       I. 改格式只能存放一幅图像。
       II. 只能存储单色、16色、256色或彩色四种图像数据之一。
       III. 图像数据有压缩或不压缩两种处理方式,压缩方式为:RLE_4 和 RLE_8。RLE_4只能处理 16 色图像数据;而 RLE_8 则只能压缩 256 色图像数据。
       IV. 调色板的数据存储结构较为特殊。

      看到这里BMP的文件格式就介绍完了,本次进行编码实现的主要是不压缩的数据格式,压缩的数据格式等到以后有机会再详细介绍。

    2.4. 再说一种坐标系

      说完了BMP文件格式,我们再说一说图像坐标系5,下面这张图片是小贾画的图像坐标系和图像的存储顺序。这张图可能有助于你理解下面代码中对于像素的提取。

    3. 编码实现

    3.1. 创建一个C(C++)项目

      首先我们打开任何一个能进行C语言编程的编译,建立一个空项目的控制台程序,新建一个CPP文件,并将Lena.bmp拷到项目文件夹中(这里我以Visual Studio 2015 为例,点击图片可以看大图)。
    新建项目图片1
    新建项目图片2
    新建项目图片3
    新建项目图片4
    在这里插入图片描述

    3.2. 编码

      在编译器中写上下面的代码(下面的代码是灰度图的读取,关于后面多波段的读取,我们以后在再介绍)。

    #include <stdio.h> // C语言代码中必须要引用的头文件
    #include <windows.h> // 图像读取的头文件
    
    // 使代码在新版本的VS中正常运行不报错
    #define _CRT_SECURE_NO_WARNINGS
    #pragma warning(disable:4996)
    
    // 定义一个结构体来读取BMP的信息
    typedef struct {
    	// 定义文件头信息
    	BITMAPFILEHEADER header;
    	// 定义位图信息头
    	BITMAPINFOHEADER info;
    	// 定义彩色表
    	RGBQUAD rgb[256];
    	// 定义位图数据指针
    	unsigned char *data;
    } BMP;
    
    // 读图像函数
    void bmpRead(const char *bmpPath, BMP &bmp) {
    	// 以二进制的方式打开图片
    	FILE *file = fopen(bmpPath, "rb");
    	// 读取文件信息头
    	fread(&bmp.header, sizeof(BITMAPFILEHEADER), 1, file);
    	// 读取位图信息头
    	fread(&bmp.info, sizeof(BITMAPINFOHEADER), 1, file);
    	// 读取彩色表
    	fread(&bmp.rgb, sizeof(RGBQUAD), 256, file);
    	// 定义位图数据内存大小
    	bmp.data = new unsigned char[bmp.info.biWidth * bmp.info.biHeight];
    	// 读取元素的位图数据
    	fread(bmp.data, sizeof(unsigned char), bmp.info.biWidth*bmp.info.biHeight, file);
    	// 关闭图片
    	fclose(file);
    }
    
    // 定一个函数将读取到bmp.data的像素灰度值存储到一个txt文档中
    void bmpCells(const char *pixelValuePath, BMP &bmp){
    	// 新建一个txt文件用于存储像素值
    	FILE *file = fopen(pixelValuePath, "w");
    	// 循环读取像素值
    	for (int i = 0; i < bmp.info.biHeight; i++)
    	{
    		for (int j = 0; j < bmp.info.biWidth; j++)
    		{
    			// 获取循环到像元的像素值
    			unsigned char pixel = bmp.data[j + i*bmp.info.biWidth];
    			// 这里我们打印一下读出的像元
    			printf("%d ", pixel);
    			// 保存到文件中
    			fprintf(file, "%d ", pixel);
    		}
    		// 打印一行后换行
    		printf("\n");
    		// 完成一行像素的保存后换行继续进行保存
    		fprintf(file, "\n");
    	}
    	// 关闭文件
    	fclose(file);
    }
    
    int main() {
    	// 定义图像结构体
    	BMP mbmp;
    	// 读取图像(如果不是按照本文的新建项目方法,建议使用绝对路径,否则可能会因为文件路径错误而报错。)
    	bmpRead("../lena.bmp", mbmp);
    	// 将像素值存储到一个txt文本中
    	bmpCells("../pixelValue.txt", mbmp);
    	// 删除指针,释放内存
    	delete[] mbmp.data;
    	// 使程序暂停,便于查看
    	scanf("……");
    
    	return 0;
    }
    

    4. 验证一下结果

    4.1. 结果图

      接下来让我们看一下运行的结果。
    在这里插入图片描述
    在这里插入图片描述

    4.2. 验证正确性

      如果你了解遥感图像处理,那么你一定会知道 ERDAS IMAGE 这个软件,现在我们就用这个软件来验证我们编码的结果是否正确。下图中是我们在ERDAS IMAGE中打开的图像像素值。
    在这里插入图片描述
      通过上面的初步对比,我们我们可以看出我们读取的像素值是正确的。

      这节的介绍我们到这里就结束了,有什么错误欢迎大家指出。下一节我继续介绍《数字图像处理(二)——BMP图像的统计》,下节将介绍如何获取图像像素的最小值、最大值、均值、标准差、计算图像的熵、以及统计图像灰度直方图。


    1. Lena图像:了解更多关于Lena图像的信息,请转到Lena图像的百度百科介绍↩︎

    2. 图像格式:BMP仅是众多图像格式中的一种,了解更多的格式请转到图像格式的百度百科介绍↩︎

    3. C语言编程入门教程:网上关于C语言的编程的内容很多。例如,菜鸟教程MOOC慕课平台。小贾这里给列出两种,仅供参考。 ↩︎

    4. BMP文件格式:关于BMP文件格式的介绍来源于《数字图像处理(第三版)》(贾永红版)。 ↩︎

    5. 图像坐标系:图像坐标系的介绍大家可以在百度百科中找到。 ↩︎

    展开全文
  • 指定路径下 单个文件夹data中所有图像 file_path = '.\data\';% 图像文件夹路径 img_path_list = dir(strcat(file_path,'*.jpg'));%获取该文件夹中所有jpg格式的图像 img_num = length(img_path_list);%获取...
    1。 指定路径下 单个文件夹data中所有图像
    
    file_path =  '.\data\';% 图像文件夹路径
    img_path_list = dir(strcat(file_path,'*.jpg'));%获取该文件夹中所有jpg格式的图像
    img_num = length(img_path_list);%获取图像总数量
    if img_num > 0 %有满足条件的图像
            for j = 1:img_num %逐一读取图像
                image_name = img_path_list(j).name;% 图像名
                image =  imread(strcat(file_path,image_name));
                fprintf('%d %d %s\n',i,j,strcat(file_path,image_name));% 显示正在处理的图像名
                %图像处理过程 省略
            end
    end
    注,上述的代码只能读取data文件夹中的图像,假设data中包含子文件夹,不能读取子文件夹中的图像。
    2. 指定路径下 多个文件夹中所有图像,该代码可以读取文件夹data中及data的所有子文件夹中的图像。
    p = genpath('.\data');% 获得文件夹data下所有子文件的路径,这些路径存在字符串p中,以';'分割
    length_p = size(p,2);%字符串p的长度
    path = {};%建立一个单元数组,数组的每个单元中包含一个目录
    temp = [];
    for i = 1:length_p %寻找分割符';',一旦找到,则将路径temp写入path数组中
        if p(i) ~= ';'
            temp = [temp p(i)];
        else 
            temp = [temp '\']; %在路径的最后加入 '\'
            path = [path ; temp];
            temp = [];
        end
    end  
    clear p length_p temp;
    %至此获得data文件夹及其所有子文件夹(及子文件夹的子文件夹)的路径,存于数组path中。
    %下面是逐一文件夹中读取图像
    file_num = size(path,1);% 子文件夹的个数
    for i = 1:file_num
        file_path =  path{i}; % 图像文件夹路径
        img_path_list = dir(strcat(file_path,'*.jpg'));
        img_num = length(img_path_list); %该文件夹中图像数量
        if img_num > 0
            for j = 1:img_num
                image_name = img_path_list(j).name;% 图像名
                image =  imread(strcat(file_path,image_name));
                fprintf('%d %d %s\n',i,j,strcat(file_path,image_name));% 显示正在处理的路径和图像名
                %图像处理过程 省略
            end
        end
    end
    展开全文
  • 1.新建一个基于对话框的工程,对话框类中定义如下变量 // Local iconic variables HObject ho_Image; // Local control variables HTuple hv_ImageFiles, hv_Index; afx_msg void OnBnClickedButton1(); /...
    配置略,可参考这篇博客点击打开链接
    http://blog.csdn.net/bettyshasha/article/details/51544203
    1.新建一个基于对话框的工程,在对话框类中定义如下变量
    	// Local iconic variables
    	HObject  ho_Image;
    
    	// Local control variables
    	HTuple  hv_ImageFiles, hv_Index;
    	afx_msg void OnBnClickedButton1();
    
    	//open window and show 
    	HTuple hv_WindowHandle;
    2.在初始化函数中,添加如下代码,打开控件窗口,窗口大小可设置,我设置的是200,150.读者可根据需要设定成需要的大小。
    BOOL CshowTestDlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    //openWindowOpenWindow(0, 0, 200, 150, (Hlong)m_hWnd, "", "", &hv_WindowHandle);
    	
    	
    }

    	

    3.新建一个按钮,并在按钮响应函数中添加如下代码:
    void CshowTestDlg::OnBnClickedButton1()
    {
    //在此添加读入图像和显示代码
    }

    将这段代码嵌入到OnBnClickedButton1()
    函数

    //手动添加图片所在文件夹路径,遍历该文件夹下图像
    	char* pfilefilter= "图片文件(*.bmp *.png *.jpg)|*.bmp;*.png;*jpg|All Files (*.*)|*.*||";
    	CFileDialog  OpenDialog(TRUE, NULL, 0, OFN_OVERWRITEPROMPT, pfilefilter, NULL);
    	CString str;
    	if (OpenDialog.DoModal() == IDOK)
    	{
    		str = OpenDialog.GetPathName();
    		int nIndex = str.ReverseFind('\\');
    		str = str.Left(nIndex);	// 获取当前打开文件的所在目录
    	}
    	char* ch = (char*)LPCTSTR(str);
    
    	HTuple htp;
    	htp = ch; /*"E:/course/solder/6"*/
    	//Image Acquisition 01: Code generated by Image Acquisition 01
    	ListFiles(htp, ((HTuple("files").Append("follow_links")).Append("recursive")),
    		&hv_ImageFiles);
    	TupleRegexpSelect(hv_ImageFiles, (HTuple("\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$").Append("ignore_case")),
    		&hv_ImageFiles);
    	{
    		HTuple end_val3 = (hv_ImageFiles.TupleLength()) - 1;
    		HTuple step_val3 = 1;
    		for (hv_Index = 0; hv_Index.Continue(end_val3, step_val3); hv_Index += step_val3)
    		{
    			ReadImage(&ho_Image, HTuple(hv_ImageFiles[hv_Index]));
    			//Image Acquisition 01: Do something
    			
    			//clear window
    			ClearWindow(hv_WindowHandle);
    			//SetPart(hv_WindowHandle, 0, 0, hv_Width, hv_Height);
    			
    			//display image
    			DispObj(ho_Image, hv_WindowHandle);
    			Sleep(1000);
    
    		}
    	}
    效果如图

    如果要在控件如,picture control里面实现,将1,2修改如下:
    配置略,可参考
    1.新建一个基于对话框的工程,在对话框类中定义如下变量
    	// Local iconic variables
    	HObject  ho_Image;
    
    	// Local control variables
    	HTuple  hv_ImageFiles, hv_Index;
    	afx_msg void OnBnClickedButton1();
    
    	//open window and show 
    	HTuple hv_WindowHandle;
     	//pcture control 控件上显示图像
    	 CRect rtWindow;
     	HWND hImgWnd;
    2.在对话框中添加picture control控件,并将ID号改为,IDC_MY_PIC.
    在初始化函数中,添加如下代码,打开控件窗口,窗口大小可设置,我设置的是200,150.读者可根据需要设定成需要的大小。
    BOOL CshowTestDlg::OnInitDialog()
    {
    	CDialogEx::OnInitDialog();
    //在picture control上显示
     hImgWnd = GetDlgItem(IDC_MY_PIC)->m_hWnd;
     GetDlgItem(IDC_MY_PIC)->GetClientRect(&rtWindow);
     OpenWindow(rtWindow.left, rtWindow.top, rtWindow.Width(), rtWindow.Height(), (Hlong)hImgWnd, "visible", "", &hv_WindowHandle);
    	
    }
    效果如图

    展开全文
  • github项目地址:...一、项目语言 C++(std=C++11) 二、操作系统 windos10+ubuntu16.04 均测试通过 三、运行方式 进入目录内 ...cd ImageCompression ...新建build目录 mkdir build cmake编译项目,生成M
    github项目地址:https://github.com/Kevinnan-teen/ImageCompression.git
    gitee项目地址:https://gitee.com/lucasnan/ImageCompression.git

    一、项目语言

    C++(std=C++11)

    二、操作系统

    windos10+ubuntu16.04 均测试通过

    三、运行方式

    1. 进入目录内

    cd ImageCompression

    1. 新建build目录

    mkdir build

    1. cmake编译项目,生成Makefile

    cmake …

    1. make编译

    make

    1. 运行

    四、文件要求

    • 目前只支持BMP24位的图像格式.
    • 提供两种压缩方式
      • 无损压缩:LZW压缩(生成文件后缀名为.lzw)
      • 有损压缩:RGB转YUV + LZW压缩(生成文件后缀名为.ylf)

    五、算法流程

    • 压缩
      • 读取bmp文件,保存54位信息头,将剩余的数据BGR数据全部转为YUV格式的数据(由于转为YUV后数据是浮点型,而为了实现压缩功能,我们丢弃部分的精度,只保存Int型数据),经过这一步转换就可以实现50%的压缩.
      • 转换后的YUV数据丢进LZW压缩算法.(注:有关LZW算法更多的信息可以参考我的个人博客 http://kevinnan.org.cn/index.php/archives/123/)
    • 解压缩
      • 读取压缩文件,同样保存bmp的54位信息头,读取剩余所有数据丢进LZW解压缩算法得到YUV数据.
      • 将YUV数据转为BGR数据,即可恢复.

    六、项目结构说明

    1. include / src : 头文件/源文件

      • image.h image.cpp : 存储图像信息

      • ImageIO.h ImageIO.cpp 读取和写入图像和压缩后的文件

      • LZWcompress.h LZWcompress.cpp : LZW编码与解码

      • tools.h tools.cpp : 常用的功能函数,如下.

      • main2.cpp : 主程序入口

    2. images : 测试图像

      • bmp_test.bmp : 测试原图
      • lzw.ylf : 有损压缩结果
      • lzw_test.lzw : 无损压缩结果
      • recoverImage.bmp : 有损压缩恢复结果
      • recoverImage_2.bmp : 无损压缩恢复结果
      • result_1.png result_2.png result_3.jpg result_4.jpg : 对比结果
    3. backup : 霍夫曼编码相关代码(因为某些原因没能实现在LZW压缩的基础上进一步做霍夫曼编码,因此将霍夫曼编码的代码放在backup文件夹下,日后有机会再做)。

    七、读取和写入图像二进制常用的函数(位于自定义的tools类下)

    • Char2Hex :将单个字符转为16进制字符串

    比如,当要读取bmp图像中连续的四个字节数据,可先定义一个空字符串,然后依次读取四个字节分别调用此函数,每个字节会生成对应的16进制字符串,拼接这四个字符串.然后将该字符串转为对应的格式即可.加入要转为int,则调用stoi(str, nullptr, 16)即可转为int型.

    string Char2Hex(uchar c){
    	const std::string hex = "0123456789ABCDEF";
    	string ret;
    	ret.push_back(hex[(c >> 4) & 0xf]); //取二进制高四位
    	ret.push_back(hex[c & 0xf]);        //取二进制低四位
    	return ret;
    }
    
    • splitStr :c++划分字符串

    由于c++ string本身并没有提供字符串划分函数,因此我自己实现了一个基于string的字符串划分函数,方便使用.

    std::vector<std::string> splitStr(const std::string &str,const std::string &pattern)
    {
        std::vector<std::string> resVec;
    	if ("" == str)
        {
            return resVec;
        }
        //方便截取最后一段数据
        std::string strs = str + pattern;
        size_t pos = strs.find(pattern);
        size_t size = strs.size();
        while (pos != std::string::npos)
        {
            std::string x = strs.substr(0,pos);
            resVec.push_back(x);
            strs = strs.substr(pos+1,size);
            pos = strs.find(pattern);
        }
        return resVec;
    }
    
    • bitset2char :8位bitset类型转为char

    在进行霍夫曼编码时,对编码后生成的01序列进行编码时,可调用c++提供的bitset函数库,然后保存到文件中可利用此函数将8位的bitset转为char方便保存.

    char bitset2char(std::bitset<8> bits)
    {
    	return (char)bitset<8>(bits.to_string()).to_ulong();
    }
    
    • Int2CharVector :32位整数转4字节char型

    在保存霍夫曼编码生成的权值表时,可将32位Int型数据转为chart字节char型,便于保存.

    std::vector<uchar> Int2CharVector(uint data){
    	std::vector<uchar> buf;
    	bitset<32> data_bit(data);
    	string data_bit_str = data_bit.to_string();
    	for(int i = 0; i < 4; i++){
    		bitset<8> data_bit_part(data_bit_str.substr(i*8, 8));
    		buf.push_back(bitset2char(data_bit_part));
    	}
    	return buf;
    }
    

    八、测试运行结果

    • 无损压缩

    可以看到原图与压缩后恢复的图像基本没有差别

    测试图片的压缩率为 C = b / b_ = 850.4KB / 1.2MB = 70.9%

    • 有损压缩

    可以看到在边缘处,原图和压缩后复原的图像有明显差别,这是与YUV数据存储的格式相关.

    测试图片的压缩率为 C = b / b_ =431.3KB / 1.2MB = 35.9%

    对比无损压缩,可以发现将BGR数据转为YUV的确可以将数据压缩50%

    项目进度记录

    2020/7/5更新

    代码风格从RGB转为YUV之后开始发生转变,原因是要开始使用STL提供的容器如vector, map等来替代c++原生的new动态数组.

    2020/7/6更新

    将YUV格式数据经过LZW编码,实现空间压缩的效果.
    最终生成图片的后缀 .ylh – YUV+LZW+Huffman

    2020/7/7更新

    完成lzw编码后的数据转换为霍夫曼编码
    霍夫曼编码文件存储格式: bmp图像信息头 + 权值表大小信息 + 权值表 + 霍夫曼编码结果

    2020/7/8更新

    霍夫曼解码部分出现问题,在读取权值表之后生成霍夫曼树时,由于数据出现的频率有重复,因此构成的霍夫曼树不唯一,导致编码和解码的结果不一样.

    解决方案一,把霍夫曼树生成的数据对应的编码代替权值表,但是要将bit序列转为char型保存在文件中后,再读取复原时会因为长度的原因会丢失编码表的信息,所以也不可取.
    解决方案二,在保存霍夫曼树生成的编码表时,可以将bit序列的长度也保存,这样就不会因为读取而丢失信息.
    最终,因为个人时间原因,我没有再去深究这个问题,即放弃使用霍夫曼编码.只采用了(1)RGB转YUV,和(2)LZW编码算法和编码YUV数据这两个步骤来实现bmp图像的压缩.我将霍夫曼编码相关的代码放在backup文件夹下.

    展开全文
  • ['C:\\Users\\zzs\\Desktop\\a\\55.bmp.txt', 'C:\\Users\\zzs\\Desktop\\a\\新建文件夹\\11.bmp.txt']
  • 使用软件:Visual Studio 2010中Visual C++ 下Win32 控制台应用程序【使用visual studio 2012也可以,2017版的貌似一般下载安装后使用会缺少一些文件,导致运行错误(新建C++项目没有导航,就会后面运行出错)】 ...
  • 图像处理之python读取bmp(1/4/8/16/24位)

    千次阅读 2020-10-14 15:54:18
    首先用Photoshop打开一张正常的jpg图片,接着储存中选择bmp格式,分别选择24位和16位,但是1,4,8位无法选择,此时新建一张画布,创建时选择8位,然后将上述图片导入画布,点击图像-模式-位图,并且按照上述
  • 用matlab批量新建和删除文件夹

    千次阅读 2017-02-28 19:00:36
    clear clc cd('E:\MyData2\test');%设置当前目录:current directory for i = 1 : 100 folderName{i} = ['movie', num2str(i)]; mkdir(folderName{i}); % 新建一个文件夹 end clear clc cd('E:\MyData2\te
  • pictureBox.Image.Save(@"C:\Users\Admin\Desktop\新建文件夹\" + iIndex.ToString() + ".bmp"); ++iIndex; } } 至于JPG格式的文件导出我还没有测试,但个人觉得可行!有兴趣的盆友可以自个儿测试下!欢迎抛砖...
  • (2)当文档程序中添加转换代码 注意:本文档由 ybdesire 参考网上资料撰写完成,代码已经做过测试,可直接复制张贴 实现过程: 一、配置 GDI 开发环境 (1) 下载 GDI+ SDK for Visual C++ 6.0 ...
  • 新建一个项目工程后主要有四个文件夹或文件. 一. src文件夹(源代码目录)。这个文件夹主要是放我们所建立的包下的各个应用程序的源文件,开发android大部分程序基本...当我们xml描述文件 图像,字符串,界面组件,
  • 1、选择文件用OpenFileDialog类 1).首先需要实例化文件类,例如OpenFileDialog openFile = new OpenFileDialog(); //创建打开文件的实例 ... openFile.Title = "请选择文件夹"; //设置弹出的对快框的标题 ...
  • MFC中有一个控件picture ...1、新建基于对话框的MFC界面程序,工程中配置CxImage库。 配置之后的结果如下: 同样release版本下配置,不过引用路径要改成Release文件夹。 同样release版本下配置,添加的l
  • imwrite 将图像写入图形文件 基本语法调用格式: imwrite(A,filename) imwrite(A,map,filename) ...imwrite 当前文件夹中创建新文件。输出图像的位深取决于 A 的数据类型和文件格式。对于大多数格式来说
  • 除了Mac上快速批量转换图像并调整其大小外,还有简单的方法,而不是分别更改每个图像。 下面,我们看一下使用Preview和Automator中的内置工具批量转换和调整图像大小。我们还将介绍一些第三方应用程序,这些应用...
  • 实际操作中,往往需要将文件夹中的文件名含有某个特定字符的文件批量提取或是处理,本文采用python编程实现这一功能。代码仅供参考,直接上代码: import os import shutil def select_files(dir, dir_out): s1...
  • matlab imwrite写入指定文件夹

    万次阅读 多人点赞 2017-11-22 14:18:53
    利用matlab的imwrite函数将图像数据写入指定的文件夹
  •  界面设想是点击“打开图片”去选择任意文件夹(英文名)中的图片,然后将图片显示picture control控件中。难点就是将Mat类型的图片显示图形控件中。为“打开图像”这一button按钮添加单击事件:Mat src; char...
  • VC++6.0 中将 JPG 格式图片转换成 BMP 格式 思路:利用 GDI+来完成 难点: (1)配置 GDI 开发环境,添加配置代码 (2)当文档程序中添加转换代码 注意:本文档由 ybdesire 参考网上资料撰写完成,代码...
  • 毕设之opencv批量生成BMP【圆】

    千次阅读 2016-05-15 21:32:49
    毕设之opencv批量生成BMP【圆】 程序思路:定义Mat变量,通过circle()函数操作Mat变量进行圆的绘制,再将Mat类型转为IplImage类型,通过cvSaveImage()函数进行BMP格式存储...1、 新建文件夹  system("md D:\\C
  • 数字图像处理

    2021-01-04 15:06:13
    #当前文件夹进行设置; 2、图像读取与输出 (1)imread函数 功能:实现多种类型图像文件的读取,如:BMP、GIF、JPEG、PNG、RAS等。 调用格式:A = imread(filename, fmt)。filename为图像文件名,可以是灰度图像,...
  • 数字图像处理复习

    千次阅读 2021-01-02 22:35:34
    #当前文件夹进行设置; 2、图像读取与输出 (1)imread函数 功能:实现多种类型图像文件的读取,如:BMP、GIF、JPEG、PNG、RAS等。 调用格式:A = imread(filename, fmt)。filename为图像文件名,可以是灰度图像,...
  • matlab-bmp2jpg

    2017-08-22 15:46:00
    %% 将文件夹LFW_align_man5pt下的5K多个子文件夹下的.bmp图片转换为.jpg close all; clear; clc; maindir = 'F:\dataset\LFW_align_man5pt\'; subdir = dir( maindir ); % 先确定子文件夹 disp('共有:'),...
  • 首先VC2010下新建一个Console应用程序,这个就不介绍了。应用程序设置中,空项目中打钩,但是编译运行时要选择Release模式,要不然会出现错误,如果选择预编译头选项该错误就不会出现,具体还不知道什么原因...
  • #目标文件夹,此处为相对路径,也可以改为绝对路径 determination = '/../../目标文件夹/' if not os.path.exists(determination): os.makedirs(determination) #源文件夹路径 path = '/../../源文件夹' folders =...
  • VC显示jpg图像

    2017-08-10 12:58:19
    VC里显示jpg图片的方法  注意:由于是主要通过COM类—IPicture实现的,不要忘记了CoInitialize...,用完了CoUninitialize();...但BMP图像在VC中的处理好像更理所当然一点,相信这种COM实现显示JPG、JPEG、GIF
  • 如何Android上使用FFmpeg解码图像参考文章如何Android用FFmpeg解码图像 ,如何Android上使用SDL2.0来显示图像参考[原]零基础学习SDL开发之Android使用SDL2.0显示BMP图 。有了以上两篇文章的基础我们就可以...
  • 自定义文件夹目录、硬盘、U盘的图标,DIY自己的视觉,让文件夹看起来更美

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,635
精华内容 1,454
关键字:

在文件夹新建bmp图像