Open sylvain-rouquette opened 5 months ago
The ratio is recalculated from the result, see this code.
I guess the result differs in openJPEG due to the wavelet decomposition and an approximation to obtain a certain number of bytes, see the documentation https://github.com/uclouvain/openjpeg/wiki/DocJ2KCodec
The problem lies in how you compute the compressed length:
int compressedLength = buf.width() * buf.height() * (int) buf.elemSize();
You seem to assume that the size of the buffer didn't change, and that the size of each element changed, when in fact it's both. You should compute the ratio based on the size of the buffer in bytes.
def in_place_compress_file_data_set(ds: FileDataset,
c_ratio: float = 14,
buff_size: int = int(3e5)) -> None:
pixel_array = ds.pixel_array
# Compression
mem_buffer = np.zeros(buff_size).astype(np.uint8)
comp = MemJ2K(mem_buffer, data=pixel_array, c_ratio=c_ratio)
compressed_pixel_data = mem_buffer[:comp.mem_pos].tobytes()
original_size = pixel_array.nbytes
compressed_size = len(compressed_pixel_data)
compression_ratio = original_size / compressed_size
# -------------------------
ds.PixelData = pydicom.encaps.encapsulate([compressed_pixel_data])
ds.file_meta.TransferSyntaxUID = pydicom.uid.JPEG2000
ds.add_new((0x0028, 0x2110), 'CS', '01')
ds.add_new((0x0028, 0x2112), 'DS', str(np.float16(compression_ratio)))
ds.add_new((0x0028, 0x2114), 'CS', "ISO_15444_1")
ds.SOPInstanceUID = pydicom.uid.generate_uid()
ds.is_implicit_VR = False
ds.is_little_endian = True
comp.mem_pos is the size of the compressed buffer.
I'm not sure I follow the reasoning. The compression ratio is defined by compressedLength, which are the compressed bytes, and uncompressed, which are the bytes of the raw image.
int compressedLength = buf.width() * buf.height() * (int) buf.elemSize();
pixel numbers => buf.width() * buf.height()
buf.elemSize() => number channels multiply by the size of pixel (1 for 8 bits, 2 for 16 bits)
For compressedLength, the Mat object is used only to store the compressed bytes. It is not an image, buf.elemSize() is always egual to 1.
If you think something is wrong with the current code, please publish a PR.
problem:
result: default value for CompressionRatioFactor is 10 LossyImageCompressionRatio is 13.332180546726
expected: LossyImageCompressionRatio should be 10