[Compression] VTM -17.0 intra 사용 방법 정리

es.Seong·2024년 6월 7일
0

Image Compression

목록 보기
3/15
post-thumbnail

Learned Image Compression 논문을 읽다보면 비교 방법론 중 VTM -17.0 Intra라는 방법이 자주 보입니다.
동영상 압축에 주로 사용하는 VVC 방법 같은데 해당 방법을 사용하기 위해 열심히 (삽질한) 기록입니다.

개발환경
OS : Linux

1. git clone

https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM/-/tree/master

작업 경로에 git clone을 통해 폴더를 불러옵니다.

2. 가이드라인 명령어 실행

만약 cmake가 없다면 cmake 설치해주셔야합니다.

cd VVCSoftware_VTM
mkdir build
cd build
cmake ..

cmake를 진행했다면 make -j를 실행합니다.

make -j

실행하면 다음과같이 Build되는 것을 확인할 수 있습니다.

3. 파이썬에서 실행

파이썬에서 subprocess 라이브러리를 통해 빌드한 VTM을 사용할 수 있습니다.
VTM에서 필요한 것은 인코더, 디코더 및 설정파일의 경로입니다.
/VVCSoftware_VTM/bin/umake/gcc-9.3/x86_64/release 경로 내에 EncoderApp, DecoderApp이 존재하며, /VVCSoftware_VTM/cfg 경로 내에 VTM intra 설정 파일이 존재합니다.
make -j 실행 중 인코더, 디코더 파일 경로를 확인할 수 있으니 반드시 확인해줘야 합니다.

def compress_image_vtm(image, quality):
    with tempfile.NamedTemporaryFile(delete=True, suffix=".yuv") as temp_input, \
         tempfile.NamedTemporaryFile(delete=True, suffix=".bin") as temp_output, \
         tempfile.NamedTemporaryFile(delete=True, suffix=".yuv") as temp_recon:

        # Convert image to YUV and save to temporary file
        width, height = image.size
        save_yuv(image, temp_input.name)
        
        # 인코더 및 디코더 경로
        encoder_path = "/VVCSoftware_VTM/bin/umake/gcc-9.3/x86_64/release/EncoderApp"  # 인코더 경로
        decoder_path = "/VVCSoftware_VTM/bin/umake/gcc-9.3/x86_64/release/DecoderApp"  # 디코더 경로
        config_file = "/VVCSoftware_VTM/cfg/encoder_intra_vtm.cfg"  # 설정파일 경로
        
        # VTM 인코딩
        subprocess.run([
            encoder_path,
            "-c", config_file,
            "-i", temp_input.name,
            "-b", temp_output.name,
            "-o", temp_recon.name,
            "--SourceWidth=" + str(width),
            "--SourceHeight=" + str(height),
            "--InputBitDepth=8",
            "--InternalBitDepth=8",
            "--QP=" + str(quality),
            "--FrameRate=1",
            "--FramesToBeEncoded=1"
        ], check=True)
        
        # VTM 디코딩
        subprocess.run([
            decoder_path,
            "-b", temp_output.name,
            "-o", temp_recon.name
        ], check=True)
        
        # 복원된 이미지 읽기
        recon_image = load_yuv(temp_recon.name, width, height)
        
        mse = np.mean((np.array(image) - np.array(recon_image)) ** 2)
        size = os.path.getsize(temp_output.name)
        if mse == 0:
            return recon_image, 100, size
        psnr = 20 * np.log10(255 / np.sqrt(mse))
        return recon_image, psnr, size
        
def process_single_image_for_format(image_path, compress_function, format_name):
    original_image = Image.open(image_path).convert('RGB')
    width, height = original_image.size
    total_pixels = width * height
    
    if format_name == "JPEG" or format_name == "JPEG2000":
        qualities = list(range(5, 101, 5))
    elif format_name == 'VTM-17.0 intra':
        qualities = list(range(45, 52, 1))
    else:
        qualities = list(range(5, 52, 5))
    
    psnr_values = []
    sizes = []

    for quality in qualities:
        _, psnr, size = compress_function(original_image, quality)
        psnr_values.append(psnr)
        sizes.append(size)

    bits_per_pixel = [size * 8 / total_pixels for size in sizes]

    # Filter out values where bits per pixel is greater than 1
    filtered_bpp_psnr = [(bpp, psnr) for bpp, psnr in zip(bits_per_pixel, psnr_values) if bpp <= 1]
    if filtered_bpp_psnr:
        bits_per_pixel_avg, psnr_values_avg = zip(*filtered_bpp_psnr)
    else:
        bits_per_pixel_avg, psnr_values_avg = [], []

    return bits_per_pixel_avg, psnr_values_avg
    
    
image_path = "/example.png" 

vtm_bpp, vtm_psnr = process_single_image_for_format(image_path, compress_image_vtm, "VTM-17.0 intra")
print("VTM BPP:", vtm_bpp)
print("VTM PSNR:", vtm_psnr)

# RD 커브 플롯
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 5))
plt.plot(vtm_bpp, vtm_psnr, marker='o', label='VTM')
plt.xlabel('Bits Per Pixel (bpp)')
plt.ylabel('PSNR (dB)')
plt.legend(loc='lower right')
plt.grid(True)
plt.show()

실행결과는 다음과 같이 출력되며, PSNR 및 Bitrate가 출력되는 것을 확인할 수 있습니다.

profile
Graduate student at Pusan National University, majoring in Artificial Intelligence

0개의 댓글