1

I want to extract the least significant bit (LSB) of each pixel in a very big image (19,566x14,321) that is in TIFF format.

An example of such an image is here: Carina Nebula This is in JPG format, but the NASA site has the TIFF.

Is there an easy way to do this in C/C++ ImageMagick or open source library?

Many thanks for any suggestions and help!

8
  • This question is off-topic on SO "Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it." Also question language tagged should contain question related to those languages. Removed Commented Nov 10, 2024 at 21:35
  • How many bits are in each sample in your source image? And how many samples per pixel? And what do you plan to do with the LSBs once you extract them? libvips is likely to be fast and efficient for this. Commented Nov 10, 2024 at 21:38
  • @MarkSetchell thank you for this. The RGB is from 0 to 255 in each channel. So, 8 bits per channel. My plan is to test for independence of the LSB in a large image. Commented Nov 10, 2024 at 21:50
  • @0___________ thank you for your comment. I am not sure why this is off-topic. I think it might be useful for all of us to know if there is an easy tool to do this in the open source library. I do see some questions here using matlab of a similar problem but not of a very large image as my example. Commented Nov 10, 2024 at 21:58
  • @user3236841 SO rules. Commented Nov 10, 2024 at 22:13

1 Answer 1

1

Not sure what speed you expect but it could be as simple as this with Pillow:

from PIL import Image
import numpy as np
Image.MAX_IMAGE_PIXELS = 933120000

# Load image as PIL Image and make into Numpy array
im = Image.open('eta.jpg')
na = np.array(im)

# Mask LSBs and ensure small storage allocation of np.uint8
LSBs = (na & 1).astype(np.uint8)

LSBs.tofile('filename.bin')

Note that you could compress the data before writing. Here's the code for gzip but you can change the word gzip to lzma or bz2 to try other methods:

# Generate some random data
LSBs = np.random.randint(2, size=(20_000, 14_000, 3), dtype=np.uint8).tobytes()

import gzip
compressed = gzip.compress(LSBs)

from pathlib import Path
Path('compressed.bin').write_bytes(compressed)

If you want to save the LSBs as a PNG, start with my original code and add this to the end:

# Mask LSBs and ensure small storage allocation of np.uint8
LSBs = (na & 1).astype(np.uint8)

# Make LSBs into PIL Image and save
pi = Image.fromarray(LSBs)
pi.save('LSBs.png')

You can also try replacing the final line with:

pi.save('LSBs.png', optimize=True)
Sign up to request clarification or add additional context in comments.

13 Comments

You can also use CImg just the same if you prefer C++. See cimg.eu and stackoverflow.com/search?q=user%3A2836621+%5Bcimg%5D
Thank you, I was wanting something that would take the TIFF/JPEG and give me a binary file of the LSB.
You can write to a binary file with LSBs.tofile('filename.bin')
Using the code above, I get: PIL.Image.DecompressionBombError: Image size (423414686 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack. Where is this limit set?
It shouldn't be quite that big! 20k x 14k by 3 bytes ~ 840MB. I'm guessing you have padded it out to 4 bytes per pixel. But if you are only storing the least significant bit then a two colour bitmap would be the method of choice (one for each channel).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.