I have a raw file of Y video plane (y.raw) extracted from raw video frame format YUV (YUV422_SEMI_PLANAR).How to convert this y.raw as image png or jpg ?
You have essentially got a single channel greyscale image with no packing or interleaving. So you have a few options:
ImageMagick at the command line,
via NetPBM PGM format and Photoshop, or GIMP
Python
ImageMagick at command line in Terminal
If you have ImageMagick installed like most Linux distros already do (or you can install it for free on Mac and Windows) you could convert it to like this in Terminal.
Say it is 640x480 pixels and 8-bit and you want a PNG:
convert -depth 8 -size 640x480 gray:y.raw result.png
Say it is 1024x768 pixels and 16 bit and you want a contrast-stretched JPG:
convert -depth 16 -size 1024x768 gray:y.raw -auto-level result.jpg
Via NetPBM PGM format and Photoshop or GIMP
Say you don't have ImageMagick, you could make the file into a NetPBM PGM (Portable Grey Map) that you can view/edit/save in GIMP, Paint, feh, Adobe Photoshop:
{ printf "P5\n640 480\n255\n"; cat y.raw; } > result.pgm
If you are unfortunate enough to be on Windows and want to do it this way, I think it would look something like this:
echo "P5" > header.txt
echo "640 480" >> header.txt
echo "255" >> header.txt
copy /b header.txt+y.raw result.ppm
Python
If you really, really want to write a bunch of Python, it might look like this:
#!/usr/local/bin/python3
from PIL import Image
file=open("y.raw",'rb')
rawdata=file.read()
file.close()
imgsize = (640,480)
# Use the PIL raw decoder
img = Image.frombytes('L',imgsize,rawdata)
img.save('result.png')
If anyone else is reading this and wishes they had a frame of Y data to play around with, you can easily create a simulated one containing a black-white gradient with ImageMagick like this:
convert -size 640x480 gradient: -depth 8 gray:y.raw
That will look like this with ls:
-rw-r--r-- 1 mark staff 307200 23 Mar 10:05 y.raw
Related
I'm working on a script, which builds an image, combines it with another image and saves it locally as an 8-bit BMP-file.
The image is then read by a ESP32 microcontroller, but the problem is that due to memorylimitations, the allowed file size is somewhat limited.
As a consequence, I made a BMP decoder for the ESP32, which supports RLE. In theory, the allowed number of bytes can still be exceeded, but only text and simple icons are to be read, so it will most likely never happen.
It uses Pillow for image processing, which now supports RLE-compression from version 9.1.0
https://github.com/python-pillow/Pillow/blob/main/docs/handbook/image-file-formats.rst
Pillow reads and writes Windows and OS/2 BMP files containing 1, L, P,
or RGB data. 16-colour images are read as P images. Support for
reading 8-bit run-length encoding was added in Pillow 9.1.0. Support
for reading 4-bit run-length encoding was added in Pillow 9.3.0.
Here's the part of the code, that combines two existing images into a new one and saves them:
img_buf = io.BytesIO() # Start converting from Matplotlib to PIL
# Supported: eps, jpeg, jpg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff, webp
plt.savefig(img_buf, format='png', transparent=True)
graph = Image.open(img_buf)
# Create empty, 8-bit canvas
new_image = Image.new('P',(600,448), (255,255,255)) # P = 8-bit indexed
new_image.paste(img,(0,0)) # Insert image 1 into canvas
new_image.paste(graph,(0,200)) # Insert image 2 into canvas at y:200
new_image.save("../output/priceeast.bmp", compression=1) # According to the docs, 1 = RLE
It saves the image, alright, but not RLE-encoded and I can't work out, how to enable it... or is RLE only supported when reading BMP, not saving?
UPDATE:
I added this line below:
subprocess.call('magick ../output/priceeast.png -type palette -compress RLE ../output/priceeast.bmp ', shell=True)
Pillow does not support writing BMP files with compression, which can be determined by investigating the source. BmpImagePlugin._write:
# bitmap info header
fp.write(
o32(header) # info header size
+ o32(im.size[0]) # width
+ o32(im.size[1]) # height
+ o16(1) # planes
+ o16(bits) # depth
+ o32(0) # compression (0=uncompressed)
+ o32(image) # size of bitmap
+ o32(ppm[0]) # resolution
+ o32(ppm[1]) # resolution
+ o32(colors) # colors used
+ o32(colors) # colors important
)
We can see here that the compression field in the output file header is hard-coded to none, indicating that compression is not supported when writing a file.
If you would like a work-around, ImageMagick can convert any image format to 8-bit RLE BMP like this:
magick INPUTIMAGE.xxx -type palette -compress RLE result.bmp # where XXX is PNG, JPG, TIFF, GIF, TGA etc
Check the result with exiftool like this:
exiftool -filename -filesize -compression result.bmp
File Name : result.bmp
File Size : 1168 bytes
Compression : 8-Bit RLE
Note that there are Python bindings to ImageMagick via wand, so you can achieve the same effect in Python like this:
#!/usr/bin/env python3
# You may need this before running on macOS
# export MAGICK_HOME=/opt/homebrew
from wand.image import Image
# Load image , or create pseudo image
with Image(filename='gradient:red-blue') as img:
img.type = 'palette'
img.compression = 'rle'
img.save(filename='result.bmp')
I have a naive question, but after a long day, I am not still able to get my answer.
I am currently loading my png image using PIL, it works well. However, some of my png
images are 16-bit per pixel. I am trying desperately to query this information, but I am not able to get it, using PIL. Indeed, if I am simply using the file system binary it works.
$ file flower_16b.png
flower_16b.png: PNG image data, 660 x 600, 16-bit/color RGB, non-interlaced
However in my python code:
img = Image.open(filename, "r")
print(img.mode)
I get RGB. Following the documentation PIL RGB means (3x8-bit pixels, true color), it look likes the image has been casted. So does it exist a way to get the depth of an image, using PIL or an other python module ?
PIL/Pillow doesn't support 48-bit images like that. One option might be OpenCV but be aware it comes as BGR not RGB:
import cv2
# Read with whatever bit depth is specified in the image file
BGR = cv2.imread('image.png', cv2.IMREAD_ANYDEPTH|cv2.IMREAD_ANYCOLOR)
# Check dtype and number of channels
print(BGR.dtype, BGR.shape)
dtype('uint16'), (768, 1024, 3)
Another option may be pyvips, which works a slightly different way, but has some good benefits:
import pyvips
im = pyvips.Image.new_from_file('image.png', access="sequential")
print(im)
<pyvips.Image 1024x768 ushort, 3 bands, rgb16>
If you are really, really stuck and can't/won't install OpenCV or pyvips, you have a couple more options with ImageMagick...
You could reduce your 3 RGB channels (16-bits each) to 3 RGB channels (8-bits each) with:
magick input.png PNG24:output.png # then open "output.png" with PIL
Or, you could separate the 3 RGB channels into 3 separate 16-bit files and process them separately with PIL/Pillow:
magick input.png -separate channel-%d.png
and you will get the red channel as a 16-bit image in channel-0.png which you can open with PIL/Pillow, the green as channel-1.png and the blue as channel-2.png
I have some raw .IMG format files which I'm converting to .jpg using ImageMagick to apply a CNN Classifier. The converted images, however have a black vertical line splitting the image into two. The part on the left side of the line should have actually been on the right side of the right part of the image. I've posted a sample image:
I used the command magick convert input_filename.IMG output_filename.jpg
Raw .IMG File
Here is how the image is supposed to look (converted manually using numpy):
How the image is actually looking (with the vertical black line using ImageMagick):
Version Details:
harshitjindal#Harshits-MacBook-Pro ~ % magick identify -version
Version: ImageMagick 7.0.10-0 Q16 x86_64 2020-03-08
https://imagemagick.org Copyright: © 1999-2020 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php Features: Cipher DPC
HDRI Modules OpenMP(3.1) Delegates (built-in): bzlib freetype heic jng
jp2 jpeg lcms ltdl lzma openexr png tiff webp xml zlib
I don't know why ImageMagick is failing to interpret the file correctly, but I can show you how to make it work.
You need to search in your file for the height, width and data type of your image, you can do that like this:
grep -E "LINES|LINE_SAMPLES|BITS" EW0220149939G.IMG
LINES = 1024
LINE_SAMPLES = 1024
SAMPLE_BITS = 8
That means your image is 1024x1024 and 8 bits/sample (1 byte). Then you need to take that number of bytes from the tail end of the file and feed them into ImageMagick. So, you need the final 1024x1024 bytes which you can get with tail or gtail (GNU tail) as you are on a Mac.
gtail -c $((1024*1024*1)) EW0220149939G.IMG | convert -depth 8 -size 1024x1024 gray:- result.jpg
If your image is 16-bit, like in your other question, you need to use:
gtail -c $((1024*1024*2)) 16-BIT-IMAGE.IMG | convert -depth 16 -size 1024x1024 gray:- result.jpg
If you dislike using gtail to get the last megabyte, you can alternatively specify an offset from the start of the file that tells ImageMagick where the pixel data starts. So, first you need the size of the header:
grep -E "RECORD_BYTES|LABEL_RECORDS" EW*IMG
RECORD_BYTES = 1024
LABEL_RECORDS = 0007
That means we need to skip 1024*7 bytes to get to the image, so the command is:
convert -size 1024x1024+$((1024*7)) -depth 8 gray:EW0220149939G.IMG result.jpg
I am working with python to convert an RGBA tiff to an RGB tiff with a white background.
I am using the library ImageMagick and GDAL.
My code looks like that:
def add_background_to_rgba_geotiff(source, destination):
convert_rgba_to_rgb_tif(source, destination)
add_metadata_to_new_geotiff_file(source, destination)
def convert_rgba_to_rgb_tif(source, destination):
# work also with BigTiff
command = ' '.join(['convert', quote(source),
'-background', 'white',
'-alpha', 'background',
'-alpha', 'off', quote(destination)])
shell_command.execute_and_log_outputs(command, shell=True)
def add_metadata_to_new_geotiff_file(source, destination):
RGBA_tif = gdal.Open(source, gdalconst.GA_ReadOnly)
RGB_tif = gdal.Open(destination, gdalconst.GA_Update)
RGB_tif.SetMetadata(RGBA_tif.GetMetadata())
RGB_tif.SetGeoTransform(RGBA_tif.GetGeoTransform())
RGB_tif.SetProjection(RGBA_tif.GetProjection())
del (RGBA_tif)
del (RGB_tif)
def execute_and_log_outputs(command, silence_errors=False, **kwargs):
shell_process = execute_async(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
**kwargs)
(out, err) = shell_process.communicate()
When I try to run my code with a tiff everything happens well but when I want to apply that on a BigTIFF (>4GB) it fails with this error:
TIFFWriteDirectoryTagData: Maximum TIFF file size exceeded.
Does someone know how to use BigTiff with ImageMagick?
Or could it be possible to do that with GDAL? For the moment when I try with GDAL, I only achieved to have a black background.
Thanks for your help.
If you check the available formats that ImageMagick knows, you will see a TIFF64:
identify -list format | grep -i tiff
EPT EPT rw- Encapsulated PostScript with TIFF preview
EPT2 EPT rw- Encapsulated PostScript Level II with TIFF preview
EPT3 EPT rw+ Encapsulated PostScript Level III with TIFF preview
GROUP4* TIFF rw- Raw CCITT Group4
PTIF* TIFF rw+ Pyramid encoded TIFF
TIFF* TIFF rw+ Tagged Image File Format (LIBTIFF, Version 4.0.9)
TIFF64* TIFF rw- Tagged Image File Format (64-bit) (LIBTIFF, Version 4.0.9)
If you try to make a TIFF like this it fails:
convert -size 20000x50000 xc:red +noise random a.tif
convert: Maximum TIFF file size exceeded. `TIFFAppendToStrip' # error/tiff.c/TIFFErrors/652.
So, force the TIFF64 delegate by prepending it to the output filename to get a BigTIFF like this:
convert -size 20000x50000 xc:red +noise random TIFF64:a.tif
and it works.
I need to increase the dpi of my image before reading with ocr in opencv. The problems are :
I do not know the dpi of my image right now
I do not know how to increase the dpi of an image
I searched in Google, and almost every answer suggests using cv2.resize
image = cv2.imread("source.png")
resized_image = cv2.resize(image, (100, 50)) #I need to change it to 300 DPI
resize only changes the size of image, but after all does not increase the dpi. I tried to use it, and then checked in Photoshop, the dpi was not changed.
How to do it with opencv?
I need to change dpi to 300, why do I need to know current dpi? Because if it is already dpi > 300, I do not need to convert it.
I do it with python.
The dpi is just a number in the JPEG/TIFF/PNG header. It is entirely irrelevant to the world and his dog until you print the image and then it determines how large the print will be given the image's dimensions in pixels.
During image processing, it is irrelevant. The only thing of any interest is the number of pixels you have. That is the ultimate determinant of image quality, or information content - however you want to describe it.
I don't believe you can set it with OpenCV. You can certainly set it with ImageMagick like this in the Terminal:
mogrify -set density 300 *.png # v6 ImageMagick
magick mogrify -set density 300 *.png # v7 ImageMagick
You can check it with:
identify -format "Density: %x x %y" SomeImage.jpg # v6 ImageMagick
magick identify -format ... as above # v7 ImageMagick
You can do similar things with exiftool in Terminal - note that exiftool is MUCH smaller and easier to maintain than ImageMagick because it is "just" a (very capable) single Perl script:
Extract image resolution from EXIF IFD1 information:
exiftool -IFD1:XResolution -IFD1:YResolution image.jpg
Extract all tags with names containing the word "Resolution" from an image|:
exiftool '-*resolution*' image.jpg
Set X/Y Resolution (density) on image.jpg:
exiftool -xresolution=300 -yresolution=300 image.jpg
Here is a little demonstration of what I mean at the beginning of my answer...
Use ImageMagick to create an image 1024x768 with no dpi information:
convert -size 1024x768 xc:black image.jpg
Now examine it:
identify -verbose image.jpg
Image: image.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: PseudoClass
Geometry: 1024x768+0+0
Units: Undefined
Colorspace: Gray
Type: Bilevel
...
...
Now change the dpi and set the dpi units and examine it again:
mogrify -set density 300 -units pixelsperinch image.jpg # Change dpi
identify -verbose image.jpg # Examine
Image: image.jpg
Format: JPEG (Joint Photographic Experts Group JFIF format)
Mime type: image/jpeg
Class: PseudoClass
Geometry: 1024x768+0+0 <--- Number of pixels is unchanged
Resolution: 300x300 <---
Print size: 3.41333x2.56 <--- Print size is now known
Units: PixelsPerInch <---
Colorspace: Gray
Type: Bilevel
...
...
And now you can see that suddenly we know how big a print will come out and that the number of pixels has not changed.
Even though this is an old post I just wanted to say that Tesseract has been tested and found to operate better when the height of the characters is around 30 pixels. Please check the following link:
https://groups.google.com/forum/#!msg/tesseract-ocr/Wdh_JJwnw94/24JHDYQbBQAJ
DPI is inherited property of graphical device - monitor, scanner, camera, etc. For example - lets say that we are scanning image, and we want to get image with better quality - so we set higher DPI value in scanner options. If no better DPI option - so we need to buy a better scanner which supports more scan resolutions. There are devices/methods which are able to achieve 100 000 DPI