Blurring a picture (Python, Jython, picture editing) - python

Trying to blur a picture in Jython. What I have does run but does not return a blurred picture. I'm kinda at a loss of what is wrong with it.
FINAL (WORKING) CODE EDITED IN BELOW. THANKS FOR HELP GUYS!
def main():
pic= makePicture( pickAFile() )
show( pic )
blurAmount=10
makeBlurredPicture(pic,blurAmount)
show(makeBlurredPicture(pic,blurAmount))
def makeBlurredPicture(pic,blurAmount):
w=getWidth(pic)
h=getHeight(pic)
blurPic= makeEmptyPicture( w-blurAmount, h )
for px in getPixels(blurPic):
x=getX(px)
y=getY(px)
if (x+blurAmount<w):
rTotal=0
gTotal=0
bTotal=0
for i in range(0,blurAmount):
origpx=getPixel(pic,x+i,y)
rTotal=rTotal+getRed(origpx)
gTotal=gTotal+getGreen(origpx)
bTotal=bTotal+getBlue(origpx)
rAverage=(rTotal/blurAmount)
gAverage=(gTotal/blurAmount)
bAverage=(bTotal/blurAmount)
setRed(px,rAverage)
setGreen(px,gAverage)
setBlue(px,bAverage)
return blurPic
The pseudo-code was as such : makeBlurredPicture(picture, blur_amount)
get width and height of picture and make an empty picture with the dimensions
(w-blur_amount, h ) call this blurPic
for loop, looping through all the pixels (in blurPic)
get and save x and y locations of the pixel
#make sure you are not too close to edge (x+blur) is less than width
Intialize rTotal, gTotal, and bTotal to 0
# add up the rgb values for all the pixels in the blur
For loop that loops (blur_amount) times
rTotal= rTotal +the red pixel amount of the picture (input argument) at the location (x+loop number,y) then same for green and blue
find the average of red,green, blue values, this is just rTotal/blur_amount (same for green, and blue)
set the red value of blurPic pixel to the redAverage (same for green and blue)
return blurPic

The problem is that you are overwriting the variable px from the outer loop which is the pixel in the blurred image with a pixel value from the original image.
So just replace your inner loop with:
for i in range(0,blurAmount):
origPx=getPixel(pic,x+i,y)
rTotal=rTotal+getRed(origPx)
gTotal=gTotal+getGreen(origPx)
bTotal=bTotal+getBlue(origPx)
In order to show the blurred picture change the last line in you main to
show( makeBlurredPicture(pic,blurAmount) )

Here is the simple way to do it:
import ImageFilter
def filterBlur(im):
im1 = im.filter(ImageFilter.BLUR)
im1.save("BLUR" + ext)
filterBlur(im1)
For a complete reference to the Image Library See: http://www.riisen.dk/dop/pil.html

def blur_image(image, radius):
blur = image.filter(ImageFilter.GaussianBlur(radius))
image.paste(blur,(0,0))
return image

Related

How to analyze only a part of an image?

I want to analyse a specific part of an image, as an example I'd like to focus on the bottom right 200x200 section and count all the black pixels, so far I have:
im1 = Image.open(path)
rgb_im1 = im1.convert('RGB')
for pixel in rgb_im1.getdata():
Whilst you could do this with cropping and a pair of for loops, that is really slow and not ideal.
I would suggest you use Numpy as it is very commonly available, very powerful and very fast.
Here's a 400x300 black rectangle with a 1-pixel red border:
#!/usr/bin/env python3
import numpy as np
from PIL import Image
# Open the image and make into Numpy array
im = Image.open('image.png')
ni = np.array(im)
# Declare an ROI - Region of Interest as the bottom-right 200x200 pixels
# This is called "Numpy slicing" and is near-instantaneous https://www.tutorialspoint.com/numpy/numpy_indexing_and_slicing.htm
ROI = ni[-200:,-200:]
# Calculate total area of ROI and subtract non-zero pixels to get number of zero pixels
# Numpy.count_nonzero() is highly optimised and extremely fast
black = 200*200 - np.count_nonzero(ROI)
print(f'Black pixel total: {black}')
Sample Output
Black pixel total: 39601
Yes, you can make it shorter, for example:
h, w = 200,200
im = np.array(Image.open('image.png'))
black = h*w - np.count_nonzero(ni[-h:,-w:])
If you want to debug it, you can take the ROI and make it into a PIL Image which you can then display. So just use this line anywhere after you make the ROI:
# Display image to check
Image.fromarray(ROI).show()
You can try cropping the Image to the specific part that you want:-
img = Image.open(r"Image_location")
x,y = img.size
img = img.crop((x-200, y-200, x, y))
The above code takes an input image, and crops it to its bottom right 200x200 pixels. (make sure the image dimensions are more then 200x200, otherwise an error will occur)
Original Image:-
Image after Cropping:-
You can then use this cropped image, to count the number of black pixels, where it depends on your use case what you consider as a BLACK pixel (a discrete value like (0, 0, 0) or a range/threshold (0-15, 0-15, 0-15)).
P.S.:- The final Image will always have a dimension of 200x200 pixels.
from PIL import Image
img = Image.open("ImageName.jpg")
crop_area = (a,b,c,d)
cropped_img = img.crop(crop_area)

Substitute pixels of an image with other images yet retaining the image

I have seen an image of a girl which is made up of multiple images of her.So I want to achieve the same thing using a python script.(I am completely new to image processing)
I am using pil library for this script.
import sys,os
from PIL import Image
img = Image.open("DSC_0149.jpg")
pixels = img.load()
for i in range(img.size[0]):
for j in range(img.size[1]):
pixels[i,j] = (i, j, 100) # I will change this to some pic image.
img.show()
I am trying first just to change the colour of pixel retaining the pic,But this code dint work.
Can anyone guide me how to achieve it.
Edit : I want to fill the picture with multiple pictures and yet RETAIN the original picture.
Something like this : http://www.photoshopessentials.com/photo-effects/photo-fill/ but in a much better way.
So first you need to edit each pixel with this to change the color:
If it is rgb:
img.putpixel((10,15),(r,g,b))
or
faster: pixels[1, 1] = (r, g, b)
otherwise:
Is it possible to change the color of one individual pixel in Python?
After knowing how to edit each pixel you have to create a small copy of your image with a resize like this:
Copy Image:
// Not tested : Make sure it's rgb
img = Image.new( 'RGB', (img.size[0],(img.size[1]), "black") # create a new black image
pixels = img.load() # create the pixel map
for i in range(img.size[0]): # for every pixel:
for j in range(img.size[1]):
pixels[i,j] = other_image_pixel[i,j] # set the colour accordingly
https://opensource.com/life/15/2/resize-images-python
Apply a Color filter to each small image to match the area color you will replace with this image.
The best way to understand the whole process is to take time to read this code in the same language, it's around 200 lines:
https://github.com/codebox/mosaic
Hope it solve your problems

how to add border around an image in opencv python

If I have an image like below, how can I add border all around the image such that the overall height and width of the final image increases but the height and width of the original image stays as-is in the middle.
The following code adds a constant border of size 10 pixels to all four sides of your original image.
For the colour, I have assumed that you want to use the average gray value of the background, which I have calculated from the mean value of bottom two lines of your image. Sorry, somewhat hard coded, but shows the general how-to and can be adapted to your needs.
If you leave bordersize values for bottom and right at 0, you even get a symmetric border.
Other values for BORDER_TYPE are possible, such as BORDER_DEFAULT, BORDER_REPLICATE, BORDER_WRAP.
For more details cf: http://docs.opencv.org/trunk/d3/df2/tutorial_py_basic_ops.html#gsc.tab=0
import numpy as np
import cv2
im = cv2.imread('image.jpg')
row, col = im.shape[:2]
bottom = im[row-2:row, 0:col]
mean = cv2.mean(bottom)[0]
bordersize = 10
border = cv2.copyMakeBorder(
im,
top=bordersize,
bottom=bordersize,
left=bordersize,
right=bordersize,
borderType=cv2.BORDER_CONSTANT,
value=[mean, mean, mean]
)
cv2.imshow('image', im)
cv2.imshow('bottom', bottom)
cv2.imshow('border', border)
cv2.waitKey(0)
cv2.destroyAllWindows()
Answer in one line
outputImage = cv2.copyMakeBorder(
inputImage,
topBorderWidth,
bottomBorderWidth,
leftBorderWidth,
rightBorderWidth,
cv2.BORDER_CONSTANT,
value=color of border
)
Try This:
import cv2
import numpy as np
img=cv2.imread("img_src.jpg")
h,w=img.shape[0:2]
base_size=h+20,w+20,3
# make a 3 channel image for base which is slightly larger than target img
base=np.zeros(base_size,dtype=np.uint8)
cv2.rectangle(base,(0,0),(w+20,h+20),(255,255,255),30) # really thick white rectangle
base[10:h+10,10:w+10]=img # this works
Add border using openCV
import cv2
white = [255,255,255]
img1 = cv2.imread('input.png')
constant= cv2.copyMakeBorder(img1,20,20,20,20,cv2.BORDER_CONSTANT,value=white)
cv2.imwrite('output.png',constant)

Image Processing use Python find black contour

I have a problem Please help me if I have an image multi 16 in 1 image I wanna find black contour in an image just one show YES if find black contour What should I do? in Image Processing use Python!
Python Image Library can give RGB data of an image. You can get RGB data simply by using
import Image
pic = Image.open('/path/to/file')
rgbdata = pic.load()
width, height = pic.size
def identify_black():
for i in range(width):
for j in range(height):
if rgbdata[i,j] == (0,0,0):
#print rgbdata[i,j]
print "Yes"
return True
break
identify_black()
You can view the data purely in terms of RGB values of ijth pixel in rgbdata[i,j]. width and height help you define the blocks.
RGB value for black is (0,0,0). So if in your image list, a block of pixels give you (0,0,0) you can use that i, j th number to find in which block you have black! In fact, you identify any color!
Hope this helps.
A very simple solution is thresholding, just set any non black pixel(0,0,0) to (255,255,255) and you will have all the contours in an image.

Pygame Changing Hue of Image

I have a question to do with the Python module pygame.
I want to change the hue of an image for a sprite, like applying a filter to the image. I have seen many posts concerning changing specific pixels from one color to another, although this is not what I want to do. I want to do something similar to what can be done in simple photo editing software such as paint.net, changing the overall color of an image. I could of course change the hue of the image in a photo editing software, but this would lead to lots of images needing to be made and loaded and managed, it would quickly become very tedious. I am hoping that there is some sort of way to change the hue of an image in pygame.
You can do this with Python PIL. Take a look at this question and answer, and especially the original question and answer that they link to:
Changing the color of an image based on RGB value
'''
Original post https://www.reddit.com/r/pygame/comments/hprkpr/how_to_change_the_color_of_an_image_in_pygame/
'''
blue_rgb = (0,0,255) red_rgb = (255,0,0) img =
pygame.image.load("sky_picture.png") # loads the picture from the path
given var = pygame.PixelArray(img)
# var.replace(([Colour you want to replace]), [Colour you want]) var.replace((blue_rgb), (red_rgb)) # replaces all blue in the picture
to red del var
"""
if the picture has some unchanged pixels left it's probably because they are not EXACTLY the rgb given for example (254,0,0) is not
(255,0,0) and won't be changed (to fix this you will have to calculate
the approx number ot just change the main picture)
"""
# I also uploaded this to grepper
The hue of each pixel in an image can be shifted using
PixelArray to
iterate over each pixel,
Surface.unmap_rgb to get a Color object from each pixel, and
Color.hsla to do the
hue shift.
# Get the pixels
pixels = PixelArray(surface)
# Iterate over every pixel
for x in range(surface.get_width()):
for y in range(surface.get_height()):
# Turn the pixel data into an RGB tuple
rgb = surface.unmap_rgb(pixels[x][y])
# Get a new color object using the RGB tuple and convert to HSLA
color = Color(*rgb)
h, s, l, a = color.hsla
# Add 120 to the hue (or however much you want) and wrap to under 360
color.hsla = (int(h) + 120) % 360, int(s), int(l), int(a)
# Assign directly to the pixel
pixels[x][y] = color
# The old way of closing a PixelArray object
del pixels
If the surface is small, this could be run in real time. However, it would be better to run once at load time, especially if the surface is large.

Categories