i have to convert a image from, rgb scale to grayscale image using only 4 lines, in "insert code part", I can do this using CV, but instead I have convert a color image to Black and White, by calculate the average of the RGB values. If the average is closer to 255, the pixel is set to white (255), otherwise to black (0). For conversion to a greyscale image, the pixel values have to be set to the averages of the RGB values in principle.i should use a weighting factor for each of the RGB values.
import matplotlib.pyplot
import numpy as np
myImage = matplotlib.pyplot.imread('flower.png')
height=myImage.shape[0]
width=myImage.shape[1]
for x in range(0, height-1):
for y in range(0,width-1):
#insert code
imgplot = matplotlib.pyplot.imshow(myImage)
matplotlib.pyplot.show()
You don't need a loop.
mono = (myImage.mean(2) >= 128) * 255
There is another alternative which is more efficient to use: PIL
you can install it using
pip install pillow \\ pip3 install pillow
and import it using import PIL
this package has a lot of different ways of converting an image into black and white but I would suggest the easiest method:
from PIL import Image
file = "~/Pictures/Test.jpg"
img = Image.open(file)
img = img.convert("L")
img.save("~/Pictures/Test-baw.jpg")
if you are interested in other methods, you can also check this out ;)
Related
I found this method really helpful and it's actually working quite accurately. BUT this uses OpenCV.. and I want to use the same method using PIL.
code using PIL instead of OpenCV:
from PIL import Image
import numpy as np
###test image
img=Image.open('')
img=img.load()
### splitting b,g,r channels
r,g,b=img.split()
### getting differences between (b,g), (r,g), (b,r) channel pixels
r_g=np.count_nonzero(abs(r-g))
r_b=np.count_nonzero(abs(r-b))
g_b=np.count_nonzero(abs(g-b))
### sum of differences
diff_sum=float(r_g+r_b+g_b)
### finding ratio of diff_sum with respect to size of image
ratio=diff_sum/img.size
if ratio>0.005:
print("image is color")
else:
print("image is greyscale")
I changed cv2.imread('') to Image.open('') and added img=img.load().
and I changed b,g,r=cv2.split(img) to r,g,b=img.split()
I know that split() method exists in PIL. but I'm having this error.
AttributeError: 'PixelAccess' object has no attribute 'split'
How can I solve this?
Thank you in advance!!
You are mixing data types like you are mixing Red Bull and Vodka.
The load method is producing the error because it converts the PIL image into a PixelAccess object, an you need a PIL image for split(). Also, count_nonzero() does not work because it operates on NumPy arrays, and you are attempting to call that method on a PIL image. Lastly, size returns a tuple (width and height) of the image, so you need to modify your code accordingly:
from PIL import Image
import numpy as np
###test image
img=Image.open("D://opencvImages//lena512.png")
### splitting b,g,r channels
r,g,b=img.split()
### PIL to numpy conversion:
r = np.array(r)
g = np.array(g)
b = np.array(b)
### getting differences between (b,g), (r,g), (b,r) channel pixels
r_g=np.count_nonzero(abs(r-g))
r_b=np.count_nonzero(abs(r-b))
g_b=np.count_nonzero(abs(g-b))
### sum of differences
diff_sum=float(r_g+r_b+g_b)
### get image size:
width, height = img.size
### get total pixels on image:
totalPixels = width * height
### finding ratio of diff_sum with respect to size of image
ratio = diff_sum/totalPixels
print("Ratio is: "+ratio)
if ratio>0.005:
print("image is color")
else:
print("image is greyscale")
Let's check out the Lena image in color and grayscale:
Color Lena returns this:
Ratio is: 2.981109619140625
image is color
And Grayscale Lena returns this:
Ratio is: 0.0
image is greyscale
I want to change the pixel value of a grayscale image using OpenCV.
Assume that I have a grayscale image and I want to convert all its pixel to 0 value one at a time. So that the resultant image is completely black. I tried this but there is no change in the image:
image = cv2.imread('test_image.png',0)
for i in range(image.shape[0]):
for j in range(image.shape[1]):
image[i, j] = 0
Result:
display the updated image
In most cases, you want to avoid using double for loops to modify pixel values since it is very slow. A better approach is to use Numpy for pixel modification since OpenCV uses Numpy arrays to display images. To achieve your desired result, you can use np.zeros to create a completely black image with the same shape as the original image.
import cv2
import numpy as np
image = cv2.imread("test_image.png", 0)
black = np.zeros(image.shape, np.uint8)
cv2.imshow('image', image)
cv2.imshow('black', black)
cv2.waitKey(0)
For example with a test image. Original (left), result (right)
I would suggest you to always try manipulating the copy of an image so that the image doesn't get affected in the wrong way. Coming to your question, you can do the following:
import cv2
image = cv2.imread('test_image.png',0)
#Creating a copy of the image to confirm right operation is performed on the image.
image_copy = image.copy()
image_copy[:,:] = [0] #Setting all values to 0.
I found something reasonably close to what I want to do here:
Python: PIL replace a single RGBA color
However, in my scenario I have images that were originally grayscale with color annotations added to the image (an x-ray with notes in color). I would like to replace any pixel that is not grayscale with random noise. My main problem is replacing values with noise and not a single color.
Edit: I figured out the random noise part, now just trying to figure out how to separate the color pixels from the pixels that were originally in grayscale.
from PIL import Image
import numpy as np
im = Image.open('test.jpg')
data = np.array(im) # "data" is a height x width x 3 numpy array
red, green, blue = data.T # Temporarily unpack the bands for readability
# Replace white with random noise...
white_areas = (red == 255) & (blue == 255) & (green == 255)
Z = random.random(data[...][white_areas.T].shape)
data[...][white_areas.T] = Z
im2 = Image.fromarray(data)
im2.show()
You could try
col_areas = np.logical_or(np.not_equal(red, blue), np.not_equal(red, green))
You could use this Pixel Editing python module
from PixelMenu import ChangePixels as cp
im = Image.open('test.jpg')
grayscalergb=(128, 128, 128) #RGB value of gray in your image
noise=(100,30,5) #You can adjust the noise based upon your requirements
outputimg=cp(im, col=grayscalergb, col2=noise, save=False,tolerance=100) #Adjust the tolerance until you get the right amount of noise in your image
Also:
I'd suggest you to use png images instead of jpg images because JPEG is designed with compression, everytime you load the image the RGB values change making it hard for your code to function perfectly everytime
I would like a way to change all of the pixels of a photo to white, except the pixels that are white or black that were already in the photo.
I tried to use PIL but I couldn't find it.
i would like the way to change all of the pixels of a photo to white, except the pixels that white or black that were already in the photo.
So basically you want to change all pixels to white except black, right? If so, then below work (note: it expect cv2lib is installed on your machine)
import cv2
import numpy as np
img = cv2.imread('my_img.jpeg')
img[img != 0] = 255 # change everything to white where pixel is not black
cv2.imwrite('my_img2.jpeg', img)
Assuming you have access to matplotlib and are willing to use it:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# read the image pixels and saves them as a numpy array
image = mpimg.imread('<your image>')
# see original image (just for testing)
plt.imshow(image)
plt.show()
# loop through all pixels, and replace those that are not strict white or black with white
for x in range(image.shape[0]):
for y in range(image.shape[1]):
if (image[x,y]!=0).all() and (image[x,y]!=1).all():
image[x,y] = [1,1,1]
# see modified image (to make sure this is what you need)
plt.imshow(image)
plt.show()
# save image
mpimg.imsave('<new name>',image)
You can probably vectorize this, but I find this more readable, depending on your performance requirements.
Also, make sure the input is in [0,1] format. If it is in [0,255] modify the above 1s with 255s.
Note: this solution works for RGB, with no alpha. If you have an alpha, you might need to modify, depending on your requirements.
Upon doing my homework, I stumbled across a problem concerning Python and image manipulation. I must say, using the Image lib is not an option. So here it is
from scipy.misc import imread,imsave
from numpy import zeros
imga = zeros([100,100,3])
h = len(imga)
w = len(imga[0])
for y in range(h):
for x in range(w):
imga[y,x] = [255,255,255]
imsave("Result.jpg",imga)
I would assume it makes my picture white, but it turns it black, and I have no idea why
It's not about the code (and I know it looks very ugly). Its just about the fact, that it is a black image.
Every color in an image is represented by one byte. So to create an image array, you should set it's dtype to uint8.
And, you don't need for-loop to set every elements to 255, you can use fill() method or slice index:
import numpy as np
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # or img[:] = 255
Easy!
Check the below Code:
whiteFrame = 255 * np.ones((1000,1000,3), np.uint8)
255 is the color for filling the bytes.
1000, 1000 is the size of the image.
3 is the color channel for the image.
And unit8 is the type
Goodluck
Here's a simple way to create a white image with a python one liner.
$ python3 -c "from PIL import Image;Image.new('RGB', (1900, 1080), color = (255,255,255)).save('Img.jpg')"
This will create a white image with a width of 1900 and hight of 1080.
When creating imga, you need to set the unit type. Specifically, change the following line of code:
imga = zeros([100,100,3], dtype=np.uint8)
And, add the following to your imports:
import numpy as np
That gives a white image on my machine.
The headline is too broad and shows up at Google first. I needed a white image and used PIL and numpy. PILlow actually works well with numpy
import numpy as np
from PIL import Image
img = np.zeros([100,100,3],dtype=np.uint8)
img.fill(255) # numpy array!
im = Image.fromarray(img) #convert numpy array to image
im.save('whh.jpg')
Just regarding the headline of this question, I did need a white image as well as a pillow input. And the solutions presented here did not work for me.
Therefore here a different way to generate white images for other purposes:
from PIL import Image
img = Image.new('RGB', (200, 50), color = (255,255,255))
Size and color may be changed in the 2nd and 3rd parameter of the Image.new()-function.
And if you want to write something on this image or save it, this would be example code for this.
from PIL import ImageFont, ImageDraw
fnt = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 30)
ImageDraw.Draw(img).text((0,0), "hello world", font=fnt, fill=(0,0,0))
img.save('test.jpg')
# Create an array with a required colours
# The colours are given in BGR [B, G, R]
# The array is created with values of ones, the size is (H, W, Channels)
# The format of the array is uint8
# This array needs to be converted to an image of type uint8
selectedColor = [75, 19, 77] * np.ones((640, 480, 3), np.uint8)
imgSelectedColor = np.uint8(np.absolute(selectedColor))