图像处理之python读取bmp(1/4/8/16/24位)

@图像处理之读取bmp(1/4/8/16/24位)

图像处理之读取bmp(1/4/8/16/24位)

之前做图像处理作业,要求用read读取bmp,但是网上好像都没有找到能够读取各种位图的python程序。。。实属无奈

首先要获得1bit,4bit,8bit,16bit和24bit的图像。首先用Photoshop打开一张正常的jpg图片,接着在储存中选择bmp格式,分别选择24位和16位,但是1,4,8位无法选择,此时新建一张画布,在创建时选择8位,然后将上述图片导入画布,点击图像-模式-位图,并且按照上述方式为8,4位图像。对于1位的图像,再点击图像-模式-位图然后储存为1位bmp格式图片即可。
在这里插入图片描述

分析:对于不同位数的bmp图片的数据构建方式不同,因此对于不同位数的bmp读取应该采用不同的方法。总体上,应当先读取bmp图片前54个字节里面关于文件头和位图信息头的信息。从中提取图片的长宽和图片位数等,然后依据这些信息构建数组,再将每一个像素的信息添加到数组的对应位置中,最后将数组以图片的形式显示,储存。
文件读取

  1. 读取文件头和位图信息头得到图片的位数bit_num;图片长宽像素值img_width,img_height;像素信息的起始字节位置to_img_data.
  2. 对于2,4,8位的bmp图像,是有调色板的,其中的信息位于54字节到to_img_data之间,因为bmp数据按照小端的顺序排列,因此读取的调色板信息应当为bgr,alpha的顺序,这里将bgr按顺序填入一个2^bit_num13的数组中,其中每种颜色占四个字节(bgr,alpha各一个)因为透明度都没有设置,因此舍弃alpha部分。
  3. 对于16和24位的bmp没有调色板,因此构建调色板这一步跳过。通过seek函数,使文件指针跳到to_img_data的位置,对于2,4,8位每个字节分别表示4,2,1个像素,对应的10进制值为调色板的索引值。因为read只能一个个字节地读取,也没找到按位读取的函数,因此自定义函数Breakup_byte,将一个字节按照2,2,2,2;4,4,或8位一个数字的方式返回,这里先将read读取的二进制转为10进制,然后通过bin将该十进制数转为二进制数形式的字符串,通过拆解字符串来达到拆解一个字节的目的。接着利用得到的像素的索引,将对应调色板中的值填入预先设定好的dax大小为(img_height*img_width)名为img_np的array中.
  4. 对于16位,图片通过2个字节表示rgb的三个值,分别占(555)字节,通过查询资料也有565方式的,但通过测试发现有一个位数在整张图片中都为0,因此推测该位数是不表示信息的。这里自定义了breakup_16byte函数,采用类似breakup_byte函数的方法将两个字节的信息输入得到对应的555的数字信息。由于这里也是小端表示的,因此读入的第二个字节应当放在第一个字节前面,同时表示的顺序也是bgr。将对应的像素值填入img_np中
  5. 对于24位,每个字节表示rgb中的一个,按照rgb的顺序填入img_np中。

注意事项:
6. 这里注意由于windows扫描都是以4字节为单位的,因此读取每一行的数据时,要是读取的数目不是4的倍数,应当继续读取无用的信息,直到为4的倍数
7. 同时注意bmp像素信息是从左到右,从下到上的。
实验过程中的问题:
8. 在进行16位bmp读取的时候发现图片整体偏暗,经过思考,每一位最大为2^5=32,无法达到最大的255值,这里应该是通过某种方式进行了归一化,通过多次测试,发现将每一个rgb数值*9是一个较为合理的值(这里查阅资料也没看到是要如何处理)

图像直方图显示:
Python中使用matplotlib的hist函数,对于灰度的bmp(2,4,8),直接读取像素的值,然后将该array展开,然后传到hist函数中。对于三个通道的bmp(16,24位),将每一个通道的array展开并显示,然后用不同的颜色在图像中显示出来。

保存为txt:
将图片像素保存到txt文件中,由于numpy中的savetxt只能保存一维或者二维的数组,因此用reshape将img_np展开,将g和b通道的值保存在r通道所有值的下放,即展开为img_height*3,img_width的尺寸

python实现

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import os
from struct import unpack
def byte_to_int(str1):
    #从一个str类型的byte到int
    result=0
    for i in range(len(str1)):
        y=int(str1[len(str1)-1-i])
        result+=y*2**i
    return result

# 具体详见代码和文件详见资源页



结果
1位
在这里插入图片描述
8位
在这里插入图片描述

16位在这里插入图片描述
24位在这里插入图片描述

  • 13
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
void CExample10View::OnSave555BiBitfields() { // TODO: Add your command handler code here if(lpBmpDataBuf==NULL) { MessageBox("当前没有打开的图"); return; } BYTE r,g,b; LPBYTE lpDest,lpSrc; int i,j; int nheapSize; CFileDialog filesavebox(FALSE,"bmp","BI_BITFIELDS.bmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"files(*.bmp)|*.bmp|",NULL); CFile file; CString strPathname; if(m_bmi.biBitCount!=24) { MessageBox("当前打开的图不是24图"); return; } memcpy(&m_newbmf,&m_bmf,sizeof(BITMAPFILEHEADER)); memcpy(&m_newbmi,&m_bmi,sizeof(BITMAPINFOHEADER)); m_newbmi.biBitCount=16; m_newbmi.biCompression=BI_BITFIELDS;//即3 m_newbmi.biSizeImage=WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; m_newbmf.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3; nheapSize=sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*m_newbmi.biHeight; if(lpnewBmpDataBuf!=NULL) { delete []lpnewBmpDataBuf; lpnewBmpDataBuf=NULL; } lpnewBmpDataBuf=new BYTE[nheapSize]; memcpy(lpnewBmpDataBuf,&m_newbmi,sizeof(BITMAPINFOHEADER)); DWORD* lp=(DWORD*)(lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)); *lp++=0x00007c00; *lp++=0x000003e0; *lp =0x0000001f; for(i=0;i<m_newbmi.biHeight;i++) { for(j=0;j<m_newbmi.biWidth;j++) { lpSrc=lpBmpDataBuf+sizeof(BITMAPINFOHEADER) +WIDTHBYTES(m_bmi.biWidth,m_bmi.biBitCount)*(m_bmi.biHeight-1-i) +j*3; lpDest=lpnewBmpDataBuf+sizeof(BITMAPINFOHEADER)+sizeof(DWORD)*3 +WIDTHBYTES(m_newbmi.biWidth,m_newbmi.biBitCount)*(m_newbmi.biHeight-1-i) +j*2; b=*lpSrc++; b&=0xf8; g=*lpSrc++; g&=0xf8; r=*lpSrc++; r&=0xf8; WORD* lp=(WORD*)lpDest; *lp=0; *lp=r<<7; *lp+=(g<>3); } } if(filesavebox.DoModal()!=IDOK) return; strPath
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奥卡姆剃刀_Jab

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值