I am trying to write a code in Python to display an altered image according to some conditionals. It is a part of LED strip displaying, but I am not experienced with image processing. Maybe someone would help me.
The image with fixed dimensions [height x weight] is loaded and code has to change the rows rearrangement in two ways:
For the first half of rows, For example for max_height = 10: [1,2,3,4,5] --> [1,3,5,7,9]
i=0
for height_pixel =< max_height/2
height_pixel=height_pixel+1
i+=1
For the second half of rows, for example for max_height = 10: [6,7,8,9,10] --> [10,8,6,4,2]
i=4
for height_pixel > max_height/2
height_pixel=(max_height/2)+1+i
i-=2
The columns are not changed.
After that printing/showing/... new image.
The code I have so far, based on adafruit library:
from PIL import Image
import adafruit_dotstar as dotstar
NUMPIXELS = 10 #Length of strip
FILENAME = "image.png" # Image file to load
# Load image and get dimensions:
IMG = Image.open(FILENAME).convert("RGB")
PIXELS = IMG.load()
WIDTH = IMG.size[0]
HEIGHT = IMG.size[1]
HEIGHT = min(HEIGHT, NUMPIXELS)
######################################################
# CONDITIONAL PART
pixelMap = IMG.load()
img = Image.new( IMG.mode, IMG.size)
pixelsNew = img.load()
for i in range(img.size[0]):
if ...
else...
#######################################################
img.show() #altered image
#here I allocating list of lists one for each column of image
COLUMN = [0 for x in range(WIDTH)]
for x in range(WIDTH):
COLUMN[x] = [[0, 0, 0, 0] for _ in range(HEIGHT)]
#converts it into 2D list [column x row]
for x in range(WIDTH): # For each column of image
for y in range(HEIGHT): # For each pixel in column
value = PIXELS[x, y] # Read RGB pixel in image
COLUMN[x][y][0] = value[0]] # R
COLUMN[x][y][1] = value[1]] # G
COLUMN[x][y][2] = value[2]] # B
COLUMN[x][y][3] = 1.0 # Brightness
#and display in a loop
#here the columns will changed after pressing the button, I will add it later, for now it is in loop
while True:
for x in range(WIDTH): # For each column of image...
DOTS[0 : DOTS.n] = COLUMN[x]
DOTS.show()
Maybe someone would give hints or help me with the code.
Best regards
I would suggest to generate a mapping array, which maps the orignal column indices to the newly ordered ones (and by the way, indices should start at 0):
first_half = [2*idx + 1 for idx in range(5)] # 1,3,5,7,9
second_half = [8-2*idx for idx in range(5)] # 8,6,4,2,0
mapping = first_half + second_half
for idx in range(HEIGHT):
new_img[idx] = IMG[mapping[idx]] # introduced new_img to avoid confusion between img and IMG
And then you should be almost done. As far as I can see you do not need to generate this COLUMN list of lists.
for column in new_img:
DOTS[0 : DOTS.n] = column # if thats the DOTS notation, I am not familiar with that part of your code
DOTS.show()
Related
So for this code to work properly, i need it to center the new image in the black space with borders around it. I've been trying to take the first image dimensions and subtract the new enlarged empty dimensions but I can't seem to get it to work. I'm not sure what to do at this point. I've managed to duplicate the picture i just need to center it now.
import numpy as np
# read in image (in the same folder)
image = cv2.imread("cones11.png")
# get size of image
numRows = image.shape[0] # height of image
numCols = image.shape[1] # width of image
print(image.shape[0])
print(image.shape[1])
#scalar
scalar = 1.2
#newdimensions nxn
n = int (scalar * numRows)
n1 = int(scalar * numCols)
shift = n/2
shift1 = n1/2
# create an empty color image
emptyIm = np.zeros((n, n1, 3)) # (size, data type)
# iterate over all the pixels of your image
for i in range(numRows): # iterate over height of image, y-coordinates
for j in range(numCols): # iteratve over the width of image, x-coordinates
# access values at a pixel:
# image[i][j][0]: blue value stored at pixel (i,j)
# image[i][j][1]: green value stored at pixel (i,j)
# image[i][j][2]: red value stored at pixel (i,j)
#image[i][j][0] = emptyIm[i][j][0]
#image[i][j][1] = emptyIm[i][j][1]
#image[i][j][2] = emptyIm[i][j][2]
emptyIm[i,j] = emptyIm[j,i] - image[int(shift)-1, int(shift1)-1]
emptyIm[i][j][0] = image[i][j][0]
emptyIm[i][j][1] = image[i][j][1]
emptyIm[i][j][2] = image[i][j][2]
#emptyIm[i][j] = emptyIm[i+n][i+n]
#enlarging image
# n = 2*emptyIm[i][j]
cv2.imshow("xd", image)
cv2.imshow("enlarged", emptyIm/255.0)
cv2.waitKey(0)```
I have some images(say 5) and each having different shapes. I want to concatenate into one single image for my project report. Can you please provide an easy way using opencv and python?
The resulting image is similar to below.
In numpy I tried something like this, it works but only for two images.
r = np.concatenate((images[1][:, :, 1], images[1][:, :, 3]), axis=1)
Getting the results that you show in the screenshot might require some more tinkering, but simply stacking the images on top of eachother can be acomplished like this:
import cv2
import numpy as np
image_names = ['original_field_1_0.PNG','original_field_1_1.PNG','original_field_1_3.PNG','original_field_1_4.PNG','original_field_1_5.PNG']
images = []
max_width = 0 # find the max width of all the images
total_height = 0 # the total height of the images (vertical stacking)
for name in image_names:
# open all images and find their sizes
images.append(cv2.imread(name))
if images[-1].shape[1] > max_width:
max_width = images[-1].shape[1]
total_height += images[-1].shape[0]
# create a new array with a size large enough to contain all the images
final_image = np.zeros((total_height,max_width,3),dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in images:
# add an image to the final array and increment the y coordinate
final_image[current_y:image.shape[0]+current_y,:image.shape[1],:] = image
current_y += image.shape[0]
cv2.imwrite('fin.PNG',final_image)
The basic idea is to find the total size of the images first, then create an array of that size and finally set the pixels in those ranges to that of each individual image while iterating downwards (or sideways, depending on what you want).
You can also implement threshold values for when you want to start another row or column.
This modification of #ajayramesh's solution worked for me. This function takes in a list of images and outputs a single image where all input images are stacked vertically:
def get_one_image(img_list):
max_width = 0
total_height = 200 # padding
for img in img_list:
if img.shape[1] > max_width:
max_width = img.shape[1]
total_height += img.shape[0]
# create a new array with a size large enough to contain all the images
final_image = np.zeros((total_height, max_width, 3), dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in img_list:
# add an image to the final array and increment the y coordinate
image = np.hstack((image, np.zeros((image.shape[0], max_width - image.shape[1], 3))))
final_image[current_y:current_y + image.shape[0], :, :] = image
current_y += image.shape[0]
return final_image
I modified code to make it a simple function, may be useful for others.
def get_one_image(images):
img_list = []
padding = 200
for img in images:
img_list.append(cv2.imread(img))
max_width = []
max_height = 0
for img in img_list:
max_width.append(img.shape[0])
max_height += img.shape[1]
w = np.max(max_width)
h = max_height + padding
# create a new array with a size large enough to contain all the images
final_image = np.zeros((h, w, 3), dtype=np.uint8)
current_y = 0 # keep track of where your current image was last placed in the y coordinate
for image in img_list:
# add an image to the final array and increment the y coordinate
final_image[current_y:image.shape[0] + current_y, :image.shape[1], :] = image
current_y += image.shape[0]
cv2.imwrite('out.png', final_image)
I am learning how to use Python for image manipulation and am trying to create an image where odd and even rows of pixels are shifted horizontally by the same amount (e.g. odd rows are shifted 10 pixels to the right and even rows are shifted 10 pixels to the left).
The image consists of a single black word printed on a white background, like this:
http://oi63.tinypic.com/2i255bn.jpg
With the code below, I can get odd and even rows of pixels in two separate images, but I am not sure how to combine them into a single one with 20 pixels total horizontal offset.
from PIL import Image
im = Image.open('myimage.bmp')
print im.size
white = 255,255,255
even = Image.new('RGB',[1024,768], white)
for i in range( im.size[0] ):
for j in range(im.size[1]):
if j % 2 == 0 :
even.putpixel(( int(i), int(j) ), im.getpixel((i,j)) )
even.show()
odd = Image.new('RGB',[1024,768], white)
for i in range( im.size[0] ):
for j in range(im.size[1]):
if j % 2 != 0 :
odd.putpixel(( int(i), int(j) ), im.getpixel((i,j)) )
odd.show()
I am new to Python and I would be really grateful for any help with this!
you can use numpy.roll to do the shift:
import numpy as np
import Image
im = Image.open("2i255bn.jpg")
d = im.getdata()
a = np.array(d, dtype=np.uint8).reshape(d.size[::-1]) # make numpy array of data
anew = np.roll(a, 10)
anew[::2] = np.roll(a, -10)[::2]
imnew = Image.fromarray(anew, mode="L")
imnew.show()
this is only valid for the grayscale picture. If you have RGB pictures, the reshape and arguments need to be adapted
As Rad suggested in the question comments, you only need to create one image and output both the odd and even pixels to their correct positions within it:
from PIL import Image
im = Image.open('myimage.bmp')
print im.size
white = 255,255,255
even = Image.new('RGB',[1024,768], white)
offset = 10
for i in range( im.size[0] ):
for j in range(im.size[1]):
x = int(i)+offset
if j % 2 == 0:
x = x+10
else:
x = x-10
even.putpixel(( x, int(j) ), im.getpixel((i,j)) )
even.show()
I added an offset to ensure the pixels don't go off the left of the canvas.
I have an image consisting of 100 pixels. for each pixel, I want to pad it with zeros (if on the edge) so that it's in the center, concatenate with neighboring pixels and generate a new 10x10 image. Thus I want to generate 100 images from the original image by sliding through each pixel along the row. e.g. for pixel[0,0], I want to add 4 zero columns on right, 4 zero rows on top, neighboring 5 column pixels on right and neighboring 5 row pixels on the bottom.
Can someone guide me on how this is done for a RGB image with numpy?
def unpickle_im(file, type):
import Image
im1 = Image.open(file)
im1p = np.asarray(im1, dtype=type)
return im1p
imc2p = unpickle_im('tmp/RGB-00000.png', 'float32')
##imc2p.shape = (10,10,3)
padded = np.zeros(10,10,3) ##Create a padded image filled with zeros
for i in xrange(im2cp.shape[0]):
for j in xrange(im2cp.shape[1]):
if(i < 5 or j < 5) :
new_im2cp = np.pad(im2cp[i:5, j:5], ((4-i,4-j),(0,0)))
else:
new_im2cp = np.pad(im2cp[i-4:i+5, j-4:j+5])
edit: adding the correct snippet after #dabhaid's post:
from PIL import Image
import numpy as np, time
im_array = np.random.rand(10,10,3)
pad = 4
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1] ):
temp_im = padded_array[i:i+10, j:j+10]
# print temp_im.shape
if i == 0 and j == 0:
new_im = temp_im[np.newaxis,...]
else:
new_im = np.vstack([new_im, temp_im[np.newaxis,...]])
I'm going to assume you have an RGB image (rather than an RGBA). As per the comments, is this what you want?
from PIL import Image
import numpy as np
image = Image.open('100.png')
im_array = np.array(image)
stack = np.array(100, 20, 20, 3) #100 of the padded arrays
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1]):
padded = np.zeros((20,20,3))
padded[9][9] = im_array[i][j]
stack[i*j] = padded
It seems wasteful, memory-wise.
edit in response to question update
instead of padding the new images conditionally, pad the original image and then just copy sub-images out of it:
from PIL import Image
import numpy as np
image = Image.open('100.png')
im_array = np.array(image)
pad = 4 #pixels
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
# pad 4 elements to the left, right, up and down, but leave the pixel values alone
# default value is zero
for i in xrange(im_array.shape[0] - (pad + pad+1)):
for j in xrange(im_array.shape[0] - (pad + pad+1)):
new_imarray = padded_array[i:i+9, j:j+9]
# do what you need with the new image
from PIL import Image
import numpy as np, time
im_array = np.random.rand(10,10,3)
pad = 4
padded_array = np.pad(im_array, ((pad,pad+1),(pad,pad+1),(0,0)), 'constant')
for i in xrange(im_array.shape[0]):
for j in xrange(im_array.shape[1] ):
temp_im = padded_array[i:i+10, j:j+10]
# print temp_im.shape
if i == 0 and j == 0:
new_im = temp_im[np.newaxis,...]
else:
new_im = np.vstack([new_im, temp_im[np.newaxis,...]])
I have an RGB video and a single keyframe from that video. In that keyframe, the user will apply a binary mask.
I want to create a mask of the video where pixels have values that exist in the keyframe's masked region.
In other words, I want to create a list of RGB pixel values that exist in the mask of the keyframe, and create a mask of all other frames on the condition that the pixel values exist within the list. Pixel values can be (0,0,0)-(255,255,255)
My current implementation, although technically correct, is extremely inefficient, and I imagine there must be something better.
count = 0
for x in sequence
img = cv2.imread(x)
curr = np.zeros(img.shape[:2],dtype = np.uint16)
for x in range(img.shape[0]):
for y in range(img.shape[1]):
tuple = (img[x][y][0],img[x][y][1],img[x][y][2])
if tuple not in dict:
dict[tuple] = count
curr[x][y] = count
count+=1
else:
curr[x][y] = dict[tuple]
newsequence.append(curr)
#in another function, generate mask2, the mask of the keyframe
immask = cv2.bitwise_and(newsequence[keyframe],newsequence[keyframe],mask=mask2[index].astype('uint8'))
immask = [x for x in immask.flatten() if x != 0]
#for thresholding purposes (if at least 80% of pixels with that value are selected in the keyframe)
valcount= np.bincount(immask)
truecount = np.bincount(newsequence[keyframe].flatten())
frameset = set(immask)
framemask = list(frameset)
framemask = [x for x in framemask if (float(valcount[x])/float(truecount[x]))>0.8]
for frame in range(0,numframes):
for val in framemask:
mask[frame] = np.where((newsequence[frame]==val),255,0).astype('uint8')