I am trying to read images in a folder and save them after doing some processes.
I using following code to save my images:
import cv2
i = 0
while i < len(bright_images):
cv2.imwrite(f'/path/image_{i}.png', cv2.cvtColor(bright_images[i],cv2.COLOR_BGR2RGB)
i += 1
But the problem is that when writing images all red colors in my images turn to be blue, colors change completely, it seems as if it saves based on BGR color instead of RGB.
How do I fix this issue?
FYI, I am reading images using this code:
def load_images(path):
image_list=[]
images= glob.glob(path)
images = natsorted(images)
for index in range(len(images)):
image= cv2.cvtColor(cv2.imread(images[index]),cv2.COLOR_BGR2RGB)
image_list.append(cv2.resize(image,(1920,1080)))
return image_list
Related
I am trying to combine 4 images, image 1 on top left, image 2 on top right, image 3 on bottom left and image 4 on bottom right. However, my images are different sizes and not sure how to resize the images to same size. I am pretty new to Python and this is my first time using PIL.
I have this so far (after opening the images)
img1 = img1.resize(img2.size)
img1 = img1.resize(img3.size)
img1 = img1.resize(img4.size)
This shall suffice your basic requirement.
This shall suffice your basic requirement.
Steps:
Images are read and stored to list of arrays using io.imread(img) in
a list comprehension.
We resize images to custom height and width.You can change IMAGE_WIDTH,IMAGE_HEIGHT as per your need with respect
to the input image size.
You just have to pass the location of n
images (n=4 for your case) to the function.
If you are
passing more than 2 images (for your case 4), it will work create 2
rows of images. In the top row, images in the first half of the list
are stacked and the remaining ones are placed in bottom row using
hconcat().
The two rows are stacked vertically using vconcat().
Finally, we convert the result to RGB image using
image.convert("RGB") and is saved using image.save().
The code:
import cv2
from PIL import Image
from skimage import io
IMAGE_WIDTH = 1920
IMAGE_HEIGHT = 1080
def create_collage(images):
images = [io.imread(img) for img in images]
images = [cv2.resize(image, (IMAGE_WIDTH, IMAGE_HEIGHT)) for image in images]
if len(images) > 2:
half = len(images) // 2
h1 = cv2.hconcat(images[:half])
h2 = cv2.hconcat(images[half:])
concat_images = cv2.vconcat([h1, h2])
else:
concat_images = cv2.hconcat(images)
image = Image.fromarray(concat_images)
# Image path
image_name = "result.jpg"
image = image.convert("RGB")
image.save(f"{image_name}")
return image_name
images=["image1.png","image2.png","image3.png","image4.png"]
#image1 on top left, image2 on top right, image3 on bottom left,image4 on bottom right
create_collage(images)
To create advanced college make you can look into this:
https://codereview.stackexchange.com/questions/275727/python-3-script-to-make-photo-collages
I have an image that is the output of a semantic segmentation algorithm, for example this one
I looked online and tried many pieces of code but none worked for me so far.
It is clear to the human eye that there are 5 different colors in this image: blue, black, red, and white.
I am trying to write a script in python to analyze the image and return the number of colors present in the image but so far it is not working. There are many pixels in the image which contain values that are a mixture of the colors above.
The code I am using is the following but I would like to understand if there is an easier way in your opinion to achieve this goal.
I think that I need to implement some sort of thresholding that has the following logic:
Is there a similar color to this one? if yes, do not increase the count of colors
Is this color present for more than N pixels? If not, do not increase the count of colors.
from PIL import Image
imgPath = "image.jpg"
img = Image.open(imgPath)
uniqueColors = set()
w, h = img.size
for x in range(w):
for y in range(h):
pixel = img.getpixel((x, y))
uniqueColors.add(pixel)
totalUniqueColors = len(uniqueColors)
print(totalUniqueColors)
print(uniqueColors)
Thanks in advance!
I solved my issue and I am now able to count colors in images coming from a semantic segmentation dataset (the images must be in .png since it is a lossless format).
Below I try to explain what I have found in the process for a solution and the code I used which should be ready to use (you need to just change the path to the images you want to analyze).
I had two main problems.
The first problem of the color counting was the format of the image. I was using (for some of the tests) .jpeg images that compress the image.
Therefore from something like this
If I would zoom in the top left corner of the glass (marked in green) I was seeing something like this
Which obviously is not good since it will introduce many more colors than the ones "visible to the human eye"
Instead, for my annotated images I had something like the following
If I zoom in the saddle of the bike (marked in green) I had something like this
The second problem was that I did not convert my image into an RGB image.
This is taken care in the code from the line:
img = Image.open(filename).convert('RGB')
The code is below. For sure it is not the most efficient but for me it does the job. Any suggestion to improve its performance is appreciated
import numpy as np
from PIL import Image
import argparse
import os
debug = False
def main(data_dir):
print("This small script allows you to count the number of different colors in an image")
print("This code has been written to count the number of classes in images from a semantic segmentation dataset")
print("Therefore, it is highly recommended to run this code on lossless images (such as .png ones)")
print("Images are being loaded from: {}".format(data_dir))
directory = os.fsencode(data_dir)
interesting_image_format = ".png"
# I will put in the variable filenames all the paths to the images to be analyzed
filenames = []
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith(interesting_image_format):
if debug:
print(os.path.join(directory, filename))
print("Analyzing image: {}".format(filename))
filenames.append(os.path.join(data_dir, filename))
else:
if debug:
print("I am not doing much here...")
continue
# Sort the filenames in an alphabetical order
filenames.sort()
# Analyze the images (i.e., count the different number of colors in the images)
number_of_colors_in_images = []
for filename in filenames:
img = Image.open(filename).convert('RGB')
if debug:
print(img.format)
print(img.size)
print(img.mode)
data_img = np.asarray(img)
if debug:
print(data_img.shape)
uniques = np.unique(data_img.reshape(-1, data_img.shape[-1]), axis=0)
# uncomment the following line if you want information for each analyzed image
print("The number of different colors in image ({}) {} is: {}".format(interesting_image_format, filename, len(uniques)))
# print("uniques.shape[0] for image {} is: {}".format(filename, uniques.shape[0]))
# Put the number of colors of each image into an array
number_of_colors_in_images.append(len(uniques))
print(number_of_colors_in_images)
# Print the maximum number of colors (classes) of all the analyzed images
print(np.max(number_of_colors_in_images))
# Print the average number of colors (classes) of all the analyzed images
print(np.average(number_of_colors_in_images))
def args_preprocess():
# Command line arguments
parser = argparse.ArgumentParser()
parser.add_argument(
"--data_dir", default="default_path_to_images", type=str, help='Specify the directory path from where to take the images of which we want to count the classes')
args = parser.parse_args()
main(args.data_dir)
if __name__ == '__main__':
args_preprocess()
The thing mentioned above about the lossy compression in .jpeg images and lossless compression in .png seems to be a nice thing to point out. But you can use the following piece of code to get the number of classes from a mask.
This is only applicable on .png images. Not tested on .jpeg images.
import cv2 as cv
import numpy as np
img_path = r'C:\Users\Bhavya\Downloads\img.png'
img = cv.imread(img_path)
img = np.array(img, dtype='int32')
pixels = []
for i in range(img.shape[0]):
for j in range(img.shape[1]):
r, g, b = list(img[i, j, :])
pixels.append((r, g, b))
pixels = list(set(pixels))
print(len(pixels))
In this solution what I have done is appended pair of pixel values(RGB) in the input image to a list and converted the list to set and then back to list. The first conversion of list to set removes all the duplicate elements(here pixel values) and gives unique pixel values and the next conversion from set to list is optional and just to apply some future list operations on the pixels.
Something has gone wrong - your image has 1277 unique colours, rather than the 5 you suggest.
Have you maybe saved/shared a lossy JPEG rather than the lossless PNG you should prefer for classified images?
A fast method of counting the unique colours with Numpy is as follows:
def withNumpy(img):
# Ignore A channel
px = np.asarray(img)[...,:3]
# Merge RGB888 into single 24-bit integer
px24 = np.dot(np.array(px, np.uint32),[1,256,65536])
# Return number of unique colours
return len(np.unique(px24))
So, I am doing this project to detect diabetic retinopathy using deep learning. I however am stuck in the preprocessing image section as the pictures that are in different folders(for diff stages of DR) wouldn't convert into grayscale nomatter how much I try.
Here is my functions that does the early preprocessing stage:
def preprocessing(conditionname,directory):
for image in os.listdir(directory):
label = eye_label(conditionname,image)
path = os.path.join(directory,image)
image = cv2.imread(path,cv2.IMREAD_COLOR) #Reading the colour images
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) #Changing coloured image into black and white
#image = cv2.addWeighted(image,10,cv2.GaussianBlur(image , (0,0) , sigma_x) ,-4 ,12)
image = cv2.resize(image,(image_size,image_size)) #Changing the size of each image
return image
Try using your debugger or IDE to check everything gives you the result you expect, one step at a time.
If you load an image, print its shape:
img = cv2.imread(...)
print(image.shape)
If you convert an image to greyscale, check it has 1 channel afterwards:
img = cv2.cvtColor(...)
print(image.shape)
If you resize an image, check its size is what you expect:
img = cv2.resize(...)
print(image.shape)
If you are going to return an image from a function, check its size and type:
print(result.shape, result.dtype)
return result
Is there a known solution to convert images from having 3 channels (RGB) to having only one channel using PIL (or Scipy)
I tried converting the image to Grayscale and saving as png as per the code below, the image still had 3 color channels.
from glob import glob
import os
import os.path
from PIL import Image
SIZE = 32, 32
# set directory
# os.chdir('..data/unprocessed_cats')
# filter all jpg and png images
IMAGE_FILES = glob('../data/validation/cats/*.jpg')
IMAGE_COUNTER = 1
print IMAGE_FILES
# iterate over files
for image_file in IMAGE_FILES:
# open file and resize
try:
im = Image.open(image_file)
except:
pass
im = im.resize(SIZE, Image.ANTIALIAS)
# save locally
output_filename = "%s.png" % IMAGE_COUNTER
# Grayscale
im.convert('LA').save(os.path.join('../data/validation', 'cats_processed', output_filename), "PNG")
# incriment image counter
IMAGE_COUNTER = IMAGE_COUNTER + 1
I tried just using im.convert('L') but that replaced the transparency with black (turning my entire image black).
I found the below code from Remove transparency/alpha from any image using PIL extremely helpful (full credits to Humphrey):
def remove_transparency(im, bg_colour=(255, 255, 255)):
# Only process if image has transparency
if im.mode in ('RGBA', 'LA') or (im.mode == 'P' and 'transparency' in im.info):
# Need to convert to RGBA if LA format due to a bug in PIL
alpha = im.convert('RGBA').split()[-1]
# Create a new background image of our matt color.
# Must be RGBA because paste requires both images have the same format
bg = Image.new("RGBA", im.size, bg_colour + (255,))
bg.paste(im, mask=alpha)
return bg
else:
return im
Removing the transparency first and then converting it with im.convert('L') returns the greyscale mode:
im = remove_transparency(im).convert('L')
Short question, I have 2 images. One is imported through:
Image = mpimg.imread('image.jpg')
While the other one is a processed image of the one imported above, this image is first converted from rgb to hls and then back. The outcome of this convertion gives a "list" which is different than the uint8 of the imported image.
When I'm trying to stick these images together with the function:
new_img2[:height,width:width*2]=image2
I don't see the second image in the combined image while by plotting the image through:
imgplot = plt.imshow(image2)
plt.show()
It works fine. What is the best way to convert the orignal to a "list" and then combine them or the "list" to uint8?
For some more information, the outcome has to be something like this:
enter image description here
Where the right side is black because the image I try to import in it has another type of array. The left image was an uint8 while the other is a "list". The second image is this one, which is saved from python:
enter image description here
Not sure how to do it the way you have show above but I have always been able to merge and save images as shown below!
def mergeImages(image1, image2, dir):
'''
Merge Image 1 and Image 2 side by side and delete the origional
'''
#adding a try/except would cut down on directory errors. not needed if you know you will always open correct images
if image1 == None:
image1.save(dir)
os.remove(image2)
return
im1 = Image.open(image1) #open image
im1.thumbnail((640,640)) #scales the image to 640, 480. Can be changed to whatever you need
im2 = Image.open(image2) #open Image
im1.thumbnail((640,480)) #Again scale
new_im = Image.new('RGB', (2000,720)) #Create a blank canvas image, size can be changed for your needs
new_im.paste(im1, (0,0)) #pasting image one at pos (0,0), can be changed for you
new_im.paste(im2, (640,0)) #again pasting
new_im.save(dir) #save image in defined directory
os.remove(image1) #Optionally deleting the origonal images, I do this to save on space
os.remove(image2)
After a day of searching I found out that both variables can be changed to the type of a float64. The "list" variable:
Image = np.asarray(Image)
This creates an float 64 from a List variable. While the uint8 can be changed to a float64 by:
Image2=np.asarray(Image2/255)
Than the 2 can be combined with:
totalImgage = np.hstack((Image,Image2))
Which than creates the wanted image.