LibTIFF - Read 16bit image into array? - image

On the LibTIFF documentation, there is no mention or sample of how to read a 16 bit RGB image. Apparently also, using the scanline functions is required for reading a 16 bit. After a few attempts I couldn't get that to work.
According to this post,
If you want to handle all kind of TIFF image wihout using
TIFFReadRGBAImage then you have to detect the image format and use
low-level interface such as TIFFReadEncodedStrip and
TIFFReadEncodedTile
My end goal is to be able to get 16 bit values for the R,G and B channels, as well as actually know where they are in the image.
In the docs for libtiff they provide this sample code for eading using the strip encoding, however, they don't explain what is in the buf you get or how to make use of it. Can anyone explain how I am supposed to read the 16 bit values from that? Also, is there a way to consistent determine the strip order so I my read image is rendered correct?
TIFF* tif = TIFFOpen("myfile.tif", "r");
if (tif) {
tdata_t buf;
tstrip_t strip;
buf = _TIFFmalloc(TIFFStripSize(tif));
for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++)
TIFFReadEncodedStrip(tif, strip, buf, (tsize_t) -1);
_TIFFfree(buf);
TIFFClose(tif);
}

Related

How to write an image to the Windows clipboard in Rust

I want to put a local image into the clipboard using Rust. I used the clipboard-win and image crates. My code is as follows, but it doesn't work.
extern crate clipboard_win;
extern crate image;
use clipboard_win::{formats, Clipboard};
use image::GenericImageView;
fn main() {
let img = image::open("C:\\Users\\Crash\\Desktop\\20190405221505.png").unwrap();
Clipboard::new()
.unwrap()
.set(formats::CF_BITMAP, &img.raw_pixels());
}
After execution, there seems to be content in the pasteboard, but there is nothing displayed after Ctrl+V. How can I correct this code?
You have multiple problems.
Format
A PNG format image is not a bitmap format image, even though it is a bitmap.
A thread on MSDN states:
There isn't a standardized clipboard format for PNG.
You can register your own format, but then only you can recognize the clipboard. If you use the standard bitmap or file format then more applications can accept your data.
Error handling
Clipboard::set can fail and it returns a Result. You need to handle this case. The compiler even told you about this:
warning: unused `std::result::Result` that must be used
--> src\main.rs:11:5
|
11 | / Clipboard::new()
12 | | .unwrap()
13 | | .set(formats::CF_BITMAP, &data);
| |________________________________________^
|
= note: #[warn(unused_must_use)] on by default
= note: this `Result` may be an `Err` variant, which should be handled
Don't ignore warnings, especially when trying to debug a problem.
Unfortunately, this is as far as I got:
use clipboard_win::{formats, Clipboard}; // 2.1.2
use image::ImageOutputFormat; // 0.21.0
fn main() {
let img = image::open("unicorn.png").unwrap();
let mut data = Vec::new();
img.write_to(&mut data, ImageOutputFormat::BMP)
.expect("Unable to transform");
Clipboard::new()
.unwrap()
.set(formats::CF_BITMAP, &data)
.expect("Unable to set clipboard");
}
Writing data to a file produces a BMP that Paint can read, but the clipboard data is still invalid. While attempting to debug the differences, I ran into low-level crashes in the library, which suggests it may not be ready for general use, despite the 2.x version number.
I believe that the root problem is that
Windows expects
A handle to a bitmap (HBITMAP).
A BITMAP is a struct with a set of information about the bitmap, such as width and height. This is likely different from the on-disk format of the bitmap.
It seems plausible that fitting the bitmap data into this expected format would go a long way to solving the problem.
Another avenue is to look into using CF_DIB instead of CF_BITMAP. Contrary to the linked forum post above, CF_DIB expects a pointer to a BITMAPINFO which has a BITMAPINFOHEADER field. This makes a reference to a BI_PNG compression, which might allow you to submit a PNG without performing transformations.
See also:
How do I encode a Rust Piston image and get the result in memory?

Using libwebp c api to create animation but only first frame is encoded

I am trying to encode a sequence of images generated in my c++ code into animated images to make viewing them easier. I picked webp and followed some code examples from the official document. I would not need to tune any parameters. As long as it is animated, it is great.
The code (https://developers.google.com/speed/webp/docs/container-api) is like this:
WebPAnimEncoderOptions enc_options;
WebPAnimEncoderOptionsInit(&enc_options);
// Tune 'enc_options' as needed.
WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
while(<there are more frames>) {
WebPConfig config;
WebPConfigInit(&config);
// Tune 'config' as needed.
WebPAnimEncoderAdd(enc, frame, timestamp_ms, &config);
}
WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
WebPAnimEncoderAssemble(enc, webp_data);
WebPAnimEncoderDelete(enc);
However, even though the input frames are double-checked and time stamp increasing, in my output file only the first frame is encoded. By setting
enc_options.verbose = true;
I see that only the first time WebPAnimEncoderAdd() ran did the coder warn my on converting YUV to rgba with loss. Am I following the wrong example or what?
Much appreciated.
This is likely what happened: only for the first time did WebPAnimEncoderAdd() triggered conversion from YUV to argb so the rgba values stays constant, even though the YUV values are changed later. To solve it, I set
frame.use_argb = true;
before
WebPPictureAlloc(&frame);
then copy in the argb bytes for each frame and it works now.

libav: where to get a reference to AV_PIX_FMT_NV12 when using cuda/cuvid?

Say I'm using av_hwdevice_find_type_by_name("cuda"), as in here. I need to convert the decoded frames to RGB using a SwsContext. I know, by experience, that when using the cuda/cuvid decoder I get frames in the AV_PIX_FMT_NV12 format, even though every struct I look at says either AV_PIX_FMT_NONE or AV_PIX_FMT_YUV420P.
On what field of what struct can I get the AV_PIX_FMT_NV12 value so I can remove my hardcoded source format on my call to SwsContext.sws_scale? Thanks!
Update:
Looks like I can get it by:
AVCodecContext* avctx;
...
frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
AVPixelFormat pixel_fmt = frames_ctx->sw_format;
...once at least one frame has been decoded. Not sure if it's the correct way though.
As for CUDA, your best bet will be when see AV_PIX_FMT_YUV420P on AVHWFramesContext::sw_format consider it as AV_PIX_FMT_NV12 and when AV_PIX_FMT_YUV420P10 it is actually AV_PIX_FMT_P010.
As far as I know, neither CUDA nor NVDEC(was CUVID) support anything other than 420 format as decoded frames.

How to interpret a binary Bitmap picture, so I know which color on which pixel i change when changing something in the Code?

I just used this code to convert a picture to binary:
import io
tme = input("Name: ")
with io.open(tme, "rb") as se:
print(se.read())
se.close()
Now it looks like this:
5MEMMMMMMMMMMMMM777777777777777777777777777777777\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95\x95MEEMMMMEEMM\x96\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97
And now I want to be able to interpret what this binary code is telling me exactly... I know it ruffly but not enough to be able to do anything on purpose. I searched the web but I didn't find anything that could help me on that point. Can you tell me how is it working or send me a link where I can read how it's done?
You can't just change random bytes in an image. There's a header at the start with the height and width, probably the date and a palette and information about the number of channels and bits per pixel. Then there is the image data which is often padded, and/or compressed.
So you need an imaging library like PIL/Pillow and code something like this:
from PIL import Image
im = Image.open('image.bmp').convert('RGB')
px = im.load()
# Look at pixel[4,4]
print (px[4,4])
# Make it red
px[4,4] = (255,0,0)
# Save to disk
im.save('result.bmp')
Documentation and examples available here.
The output should be printed in hexadecimal format. The first bytes in bitmap file are 'B' and 'M'.
You are attempting to print the content in ASCII. Moreover, it doesn't show the first bytes because the content has scrolled further down. Add print("start\n") to make sure you see the start of the output.
import io
import binascii
tme = 'path.bmp'
print("start") # make sure this line appears in console output
with io.open(tme, "rb") as se:
content = se.read()
print(binascii.hexlify(content))
Now you should see something like
start
b'424d26040100000000003...
42 is hex value for B
4d is hex value for M ...
The first 14 bytes in the file are BITMAPFILEHEADER
The next 40 bytes are BITMAPINFOHEADER
The bytes after that are color table (if any) and finally the actual pixels.
See BITMAPFILEHEADER and BITMAPINFOHEADER

Opencv cvSaveImage

I am trying to save an image using opencv cvSaveImage function. The problem is that I am performing a DCT on the image and then changing the coefficients that are obtained after performing the DCT, after that I am performing an inverse DCT to get back the pixel values. But this time I get the pixel values in Decimals(e.g. 254.34576). So when I save this using cvSaveImage function it discards all the values after decimals(e.g. saving 254.34576 as 254) and saves the image. Due to this my result gets affected. Please Help
"The function cvSaveImage saves the image to the specified file. The image format is chosen depending on the filename extension, see cvLoadImage. Only 8-bit single-channel or 3-channel (with 'BGR' channel order) images can be saved using this function. If the format, depth or channel order is different, use cvCvtScale and cvCvtColor to convert it before saving, or use universal cvSave to save the image to XML or YAML format."
I'd suggest investigating the cvSave function.
HOWEVER, a much easier way is to just write your own save/load functions, this would be very easy:
f = fopen("image.dat","wb");
fprintf(f,"%d%d",width,height);
for (y=0 to height)
for (x=0 to width)
fprintf(f,"%f",pixelAt(x,y));
And a corresponding mirror function for reading.
P.S. Early morning and I can't remember for the life of me if fprintf works with binary files. But you get the idea. You could use fwrite() instead.

Resources