I'm working on a program where I open an image file(jpg), edit some of the pixels, and save the image with a new file name. It seems, however, that even when I am not editing any pixels, they are still being altered. This is a quick sample I wrote up. All I am doing is opening an image and saving it with a different name.
import Image
img1 = Image.open('image.jpg')
print img1.getpixel((0,0))
img1.save('testimage.jpg')
img2 = Image.open('testimage.jpg')
print img2.getpixel((0,0))
The output of the first print statement is (253,254,248) and the output of the second is (253,251,255). Why are the Green and Blue values changing if I am doing absolutely nothing to the image?
JPEGs are lossy: saving a JPEG may result in quality loss and thus changed pixels. If you want to edit without (further) losing quality, save as .png or some other lossless format instead.
Related
I am trying to create an image made up of coloured squares. I only need each square to be one pixel large, as it is just a single block colour. However, when I use this code, the image generated is extremely blurry. Is there anyway to make the boarders sharp?
def fancycolnw2(seq,m):
data=numbwall(seq,m)
#print(data)
for i in range(len(data)):
for j in range(len(data[i])):
if data[i][j]==' ':
data[i][j]=-1
im = Image.new('RGBA', (len(data[0]),len(data))) # create the Image of size 1 pixel
#print(data)
for i in range(len(data)-1):
for j in range(len(data[i])-1):
#print(i,j)
if data[i][j]==-1:
im.putpixel((j,i), ImageColor.getcolor('black', 'RGBA'))
if data[i][j]==0:
#print('howdy')
im.putpixel((j,i), ImageColor.getcolor('red', 'RGBA'))
if data[i][j]==1:
im.putpixel((j,i), ImageColor.getcolor('blue', 'RGBA'))
if data[i][j]==2:
im.putpixel((j,i), ImageColor.getcolor('grey', 'RGBA'))
im.show()
im.save('simplePixel.png') # or any image format
The result I get looks like this:
Image
It is the correct image, I just wish the boundaries between pixels were sharp. Any help would be greatly appreciated!
The image is perfectly sharp, but rather small. I suspect that you are "zooming in" to view it clearer, and that whatever program you are zooming with is filtering the image, because with most images this looks better. You need to find a viewing program that uses "nearest neighbour" resampling when zooming in, or generate a larger image to start with, for example by setting a 4-by-4 pixel block rather than individual pixels.
(Also, the code says "# or any other image format". Don’t use JPEG for this, as the lossy compression will likely wreck your image.)
I have got a code that does motion detection. It takes video as an input and then when an object comes to the scene, background changes and code publishes "object is seen" as text on that detected frame.
My question is that how do I save frames "when objects are seen" into folders( both for colorful and gray images)? I understand that I can write that frames using " cv2.imwrite("frame%d.jpg" % count, resizedFrame)" but unfortunately it does not work.
How do I save those detected frames to "colorful" and "gray" folders?
You have to read the image first by cv2.imread() and then cv2.imwrite()
here is a small example
import
cv2
# read image as grey scale
grey_img=cv2.imread('/home/img/python.png',cv2.IMREAD_GRAYSCALE)
# save image
status=cv2.imwrite('/home/img/python_grey.png',grey_img)
print("Image written to file-system : ",status)
If you're don't have the folder path then use this
status=cv2.imwrite('python_grey.png',grey_img)
it will save the photo in default folder in which you save your .py file
if you want to save different images here is the code
import cv2
import time
# for number of images you need different names so set name automatically
name=str(time.time())+str(.png))
# read image as grey scale
grey_img=cv2.imread('/home/img/python.png',cv2.IMREAD_GRAYSCALE)
# save image
status=cv2.imwrite('%s'%name,grey_img)
print("Image written to file-system : ",status)
Okay, first thing first. This is a near duplicate of this question.
However, the issue I am facing is slightly different in a critical way.
In my application, I read a generic file name in, load said image, and display it. Where it gets tricky is I have overlay the appearance of being 'highlighted'. To do this, I was using the Image.blend() function, and blending it with a straight yellow image.
However, when dealing with blend, I was fighting the error that the two images are not compatible to be blended. To solve this, I opened the sample image I had in paint, and just pasted yellow over the whole thing, and saved it as a copy.
It just occurred to me that this will fail when a different type of image is read in by file name. Remember this needs to be generic.
So my question is: Instead of making a copy of the image manually, can I get python to generate one by copying the image and modifying it so it is solid yellow? Note: I do not need to save it after, so just making it happen is enough.
Unfortunately, I am not allowed to share my code, but hopefully the following will give an idea of what I need:
from PIL import Image
desiredWidth = 800
desiredHeight = 600
primaryImage = Image.open("first.jpg").resize((desiredWidth, desiredHeight), Image.ANTIALIAS)
# This is the thing I need fixed:
highlightImage = Image.open("highlight.jpg").resize((desiredWidth, desiredHeight), Image.ANTIALIAS)
toDisplay = Image.blend(primaryImage, highlightImage, 0.3)
Thanks to anyone who can help.
Sounds like you want to make a new image:
fill_color = (255,255,0) #define the colour as (R,G,B) tuple
highlightImage = Image.new(primaryImage.mode, #same mode as the primary
primaryImage.size, #same size as the primary
fill_color)#and the colour defined above
this creates a new image with the same mode and size as the already opened image, but with a solid colour. Cheers.
Also if you are using Pillow instead of original PIL you can even get the color by name:
from PIL.ImageColor import getcolor
overlay = 'yellow'
fill_color = getcolor(overlay, primaryImage.mode)
I am trying to get the Python 2.7 PIL Library to work with JPEG images that are only available as a stream coming from a HDD image and are not complete.
I have set the option:
ImageFile.LOAD_TRUNCATED_IMAGES = True
And load the stream as far as it is available (or better said: as far as I am 100% sure that this data is still a image, not some other file type). I have tested different things and as far as I can tell (for JPEGs) PIL only accepts it as a valid JPEG Image if it finds the 0xFFDA (Start of Scan Marker). This is a short example of how I load the data:
from PIL import Image
from StringIO import StringIO
ImageFile.LOAD_TRUNCATED_IMAGES = True
with open("/path/to/image.raw", 'rb') as fp:
fp.seek("""jump to position in image where JPEG starts""")
data = fp.read("""number of bytes I know that those belong to that jpeg""")
img = Image.open(StringIO(data)) # This would throw exception if the data does
# not contain the 0xffda marker
pixel = img.load() # Would throw exception if LOAD_TRUNCATED_IMAGES = false
height,width = img.size
for i in range(height):
for j in range(width):
print pixel[i,j]
On the very last line I expected (or hoped) to see at least the read pixel data to be displayed. But for every pixel it returns (0,0,0).
The Question: Is what I am trying here not possible with PIL?
Some weeks ago I tried the same with a image file I truncated myself, simply by cutting data from it with an editor. It worked for the pixel-data that was available. As soon as it reached a pixel that I cut off, the program threw an exception (I will try this again later today to make sure that I am not remembering wrong).
If somebody is wondering why I am doing this: I need to make sure that the image/picture inside that hdd image is in consecutive blocks/clusters and is not fragmented. To make sure of this I wanted to use pixel matching.
EDIT:
I have tried it again and this is what I have seen.
I opened a truncated image in GIMP and it showed me a few pixel lines in the upper part, but PIL was not able to at least give me the RGB values of those pixels. It always returns (0,0,0).
I made the image slightly bigger such that the lower 4/5 of the image was not visible, but that was enough for PIL to show me the RGB values that were available. Everything else was (0,0,0).
I am still not 100% sure whether PIL can show me the RGB values, even if only view pixel-data is available.
I would try it with an uncompressed format like TGA. JPG being a compressed format may not make any sense to extract pixels from an incomplete image. JPEG actually stores the parameters for equations that describe the image, not pixel values. When you query a JPEG for a pixel value it evaluates the equations at that point and returns the result.
I have the same problem with Pillow==9.2.0
Let's downgrade to Pillow==8.3.2 and it works.
I don't really know about streaming, but I think that you simply cannot access rgb value the way you do.
Try:
rgb_im = img.convert('RGB')
r, g, b = rgb_im.getpixel((i, j))
I have some experiments with JPEG, the doc said "100 completely disables the JPEG quantization stage."
However, I still got some pixel modification during saving. Here is my code:
import Image
red = [20,30,40,50,60,70];
img = Image.new("RGB", [1, len(red)], (255,255,255))
pix = img.load()
for x in range(0,len(red)):
pix[0,x] = (red[x],255,255)
img.save('test.jpg',quality=100)
img = Image.open('test.jpg')
pix = img.load()
for x in range(0,len(red)):
print pix[0,x][0],
I got unexpected output: 22 25 42 45 62 65
What should I do to preserve the pixel value ? Please note that I also tried with PHP using imagejpeg and It gives me the correct value when quality=100.
I can use png to preserve, but I want to know the reason behind this and if there is any option to avoid
JPEG consists of many different steps, many of which introduce some loss. By using a sample image containing only red, you've probably run across the worst offender - downsampling or chroma subsampling. Half of the color information is thrown away because the eye is more sensitive to brightness changes than color changes.
Some JPEG encoders can be configured to turn off subsampling, including PIL and Pillow by setting subsampling=0. In any case it won't give you a completely lossless file since there are still other steps that introduce a loss.
JPEG will always carry risk of lossyness, see Is Jpeg lossless when quality is set to 100?.
Your best bet is to use another format, especially if your experiments are for science :) Even if you're forced to start with JPEG (which seems unlikely) you should immediately convert to a lossless format for any kind of analysis and modification.
If you really want to try lossless JPEG work with python you can try jpegtran, "the lossless jpeg image transformation software from the Independent Jpeg Group", but as #Mark notes, this won't get you very far.
By the way, quantization is used in lossy or lossless compression alike, so my guess is that
...100 completely disables the JPEG quantization stage.[1]
simply means that it's not compressed at all.
Believe I've figured out how to keep the current color subsampling and other quality details:
from PIL import Image, JpegImagePlugin as JIP
img = Image.open(filename)
img.save(
filename + '2.jpg', # copy
format='JPEG',
exif=img.info['exif'], # keep EXIF info
optimize=True,
qtables=img.quantization, # keep quality
subsampling=JIP.get_sampling(img), # keep color res
)
Per https://www.exiv2.org/tags.html I've found that the YCbCrSubSampling tag is not kept in EXIF in JPEG files:
In JPEG compressed data a JPEG marker is used
instead of this tag.
This must be why there is another function in a seemingly out of the way place to to grab it.
(Believe I found it here: https://newbedev.com/determining-jpg-quality-in-python-pil)