[Multimedia] Binary Image to 1 Bit

DongHyeon·2023년 10월 16일
0

Binary Image (이진 영상)

  • 이진 영상은 각 픽셀이 오직 두가지의 값 중 하나만을 가지는 이미지.
  • 일반적으로 픽셀 값은 0과 1 또는 0과 255 중 하나의 이진 값을 가지고 있음.
  • 일반적으로 물체의 존재와 부재를 나타내는 데 사용되고 있음.
  • 정보 손실이 많고, 묘사력이 낮지만 일부 응용프로그램 등에서 물체 감지나 패턴 인식, 이미지 압축과 같은 상황에서 유용하게 활용되고 있음.

앞서 설명된 이진영상 이미지를 1-bit 파일로 압축하여 저장하고, 나타내는 방식을 서술

이진 영상의 경우 영상 픽셀의 값을 0과 1 두가지 값만을 가지고 있기 때문에 1byte씩 입력을 받는 8-bit 이미지와 다르게, 1-bit 즉 1byte당 8개의 pixel 값을 보유하도록 나타낼 수 있다.

예를 들어 1byte가

pixel8-bit1-bit
0000000000
1000000011
2000000000
3000000000
4000000000
5000000011
6000000000
7000000011

라면, 8-bit 파일은 한 픽셀을 표현하는 데, 8개의 Bit를 사용하여 표현하지만 1-bit 파일은 한 픽셀을 표현하는 데 1 bit밖에 사용하지 않아 영상의 용량이 1/8 수준으로 압축되게 된다.

특징

  • 이진 영상만 출력이 가능하고, 각 픽셀 역시 0또는 1의 값만 가지고 있다.
  • 텍스트나 선 그림, 바코드 등과 같은 간단한 이미지를 출력하는 데 사용된다.
  • 용량이 매우 작기 때문에 빠른 속도로 출력물이 형성된다.

lena512.raw

흑백 영상

영상 크기


262KB 임으로 확인할 수 있다.

Binary Image: 8-bit

해당 영상을 이진 영상으로 8-bit Image로 저장하고 Hex editor를 통해 값을 열어보자

작성 코드

# Pillow 라이브러리에서 Image호출
from PIL import Image
# 파일 경로 지정 (lena512.raw)
file_path =  "lena512.raw"
# 새로운 RGB형식의 이미지 생성, 이미지 크기는 512,512
img=Image.new("RGB",(512,512))
# pix에 이미지 로드
pix=img.load()
# 데이터 파일을 이진법 모드로 open
file=open(file_path,'rb')
# 이진 데이터를 파일에 쓸 준비
out_file=open("lena512_binary.raw",'wb')
# 파일에서 데이터를 읽어오고
data=file.read()
# 파일을 닫음
file.close()
# 생성된 RGB형식의 이미지의 pixel값에 숫자를 대입하는데
for y in range(512):
    for x in range(512):
        # 127을 기준으로 이보다 높으면 255(흰색) 낮으면 0(검정색)으로 표현
        tmp=255 if data[y*512+x]>127 else 0
        pix[x,y]=(tmp,tmp,tmp)
        # 255라면 1 저장, else 0 저장
        if tmp==255:
            b=bytes([1])
        else:
            b=bytes([0])
        out_file.write(b) 
# 이미지 출력
img.show()
out_file.close()

출력 영상

영상 크기

위와 같이 8-bit 형식으로 이진영상을 저장하게 되면 0 또는 1 (0 또는 255)의 값을 저장하지만 전체적인 bit수 차이는 없기 때문에 용량은 변하지 않는 것을 확인할 수 있음.

저장 형식


와 같이 1 byte 당 1 pixel 값을 대응시켜 표현한 방식이다.

Binary Image: 1-bit

lena512.raw파일의 값을 1bit형식 (+ little Endian 방식) 으로 저장하고 출력해보자.

변환 및 저장 작성 코드

# Pillow 라이브러리에서 Image호출
from PIL import Image
# 파일 경로 지정 (lena512.raw)
file_path="lena512.raw"
# 새로운 RGB형식의 이미지 생성, 이미지 크기는 512,512
img=Image.new("RGB",(512,512))
# pix에 이미지 로드
pix=img.load()
# 데이터 파일을 이진법 모드로 open
in_file=open(file_path,'rb')
# 이진 데이터를 파일에 쓸 준비
out_file=open("lena512_1bit.raw",'wb')
# 1바이트크기의 바이너리 데이터 생성
b=bytearray(1)
# 512,512 byte를 8로 나누어 값을 하나씩 채워넣는데,
for i in range(512*512//8):
    # 한번에 8byte의 데이터씩 읽어옵니다.
    data=in_file.read(8)
    b[0]=0b0000000 #b를 초기화 하고
    for j in range(8):
        # 높은 bit 순대로 낮은 bit에 저장 : Little Endian
        # ex) data=[0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08] 이라면 1부터 꺼내 마지막 bit에 넣음. 
        # 즉 [0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01]순으로 값을 계산하고 b에 채워넣음 
        b[0]|=0b00000001<<j if data[j]>127 else 0b00000000
    out_file.write(b) #out_file에 값을 쓰고
# 파일을 닫음
in_file.close()
out_file.close()

1-bit image 출력 작성 코드

# Pillow 라이브러리에서 Image호출
from PIL import Image
# 파일 경로 지정 (lena512_1bit.raw)
file_path="lena512_1bit.raw"
# 데이터에 이진법 모드로 open
with open(file_path,'rb') as file:
    data=file.read()
# 새로운 RGB형식의 512,512크기의 이미지 생성
image=Image.new("RGB",(512,512))
#pix에 이미지 로드
pix=image.load()
# index 설정
byte_idx=0
bit_idx=0
# 각 픽셀에 반복하는 데,
for y in range(512):
    for x in range(512):
        # 이미지의 한 byte당 8개의 pixel에 각각 대입
        # [0,1,2,3,4,5,6,7]자리의 수가 [7,6,5,4,3,2,1,0]자리에 올 수 있도록 하나씩 우편으로 이동하며 값을 꺼내와서 
        bit=(data[byte_idx]>>bit_idx)&0x01
        # 해당 비트가 1이라면 255(흰색), 0이라면 0(검정색)
        tmp=255 if bit==1 else 0
        # 이진영상을 표현
        pix[x,y]=(tmp,tmp,tmp)
        # 다음 byte로 넘어감
        bit_idx+=1
        if bit_idx==8:
            bit_idx=0
            byte_idx+=1
# 이미지 출력
image.show()

출력 영상

영상 크기

로 262KB 크기의 8-bit image에 비해, 1/8 용량의 이미지가 생성된다.

영상 형식

다소 헷갈릴 수 있는 형태를 띄고 있는데, 예를 들어 0x12(19)번 째 값이 31인 byte를 보자!
2진법으로 나타내면 0x31=0b00110001 이다.
즉, 이미지의 8픽셀에 값이 [1,0,0,0,1,1,0,0]으로 채워진다는 것인데, 이는 (512,512)크기의 이미지에서 pix[x,y]=>(144,0)~(151,0)까지 순차적으로 값이 채워진다.

profile
I'm Free!

0개의 댓글