Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image Cropping using Python

I am new to Python coding and I am writing a program in which I will be cropping an entered image and then saving it in a location. Now, I am being able to do this using a combination of PIL and pygame. But the problem is that, when I am selecting the image from the open pygame window, the selection area is totally opaque and I am not able to see through the region I am selecting. This is causing problems for my boss who wants to be able to see through it as he selects. For you guys to better understand the problem, I am writing my code here:

import pygame, sys 
from PIL import Image 

pygame.init()

def displayImage( screen, px, topleft):
     screen.blit(px, px.get_rect())
     if topleft:
         pygame.draw.rect( screen, (128,128,128), pygame.Rect(topleft[0], topleft[1], pygame.mouse.get_pos()[0] - topleft[0], pygame.mouse.get_pos()[1] - topleft[1]))
     pygame.display.flip()  

def setup(path):
     px = pygame.image.load(path)
     screen = pygame.display.set_mode( px.get_rect()[2:] )
     screen.blit(px, px.get_rect())
     pygame.display.flip()
     return screen, px

def mainLoop(screen, px):
     topleft = None
     bottomright = None
     n=0
     while n!=1:
         for event in pygame.event.get():
             if event.type == pygame.MOUSEBUTTONUP:
                 if not topleft:
                     topleft = event.pos
                 else:
                     bottomright = event.pos
                     n=1
         displayImage(screen, px, topleft)
     return ( topleft + bottomright )

if __name__ == "__main__":
     input_loc="C:\pic1.PNG"
     output_loc="C:\pic2.PNG"
     screen, px = setup(input_loc)
     left, upper, right, lower = mainLoop(screen, px)
     im = Image.open(input_loc)
     im = im.crop(( left, upper, right, lower))
     pygame.display.quit()
     im.save(output_loc)

Any help is appreciated. Regards.

like image 881
Arnab Ghosal Avatar asked May 26 '11 09:05

Arnab Ghosal


People also ask

How do you cut part of an image in Python?

The image processing library Pillow (PIL) of Python provides Image. crop() for cutting out a partial area of an image.

How do you crop an image in Python OpenCV?

There is no specific function for cropping using OpenCV, NumPy array slicing is what does the job. Every image that is read in, gets stored in a 2D array (for each color channel). Simply specify the height and width (in pixels) of the area to be cropped. And it's done!

How do I crop multiple images in Python?

You can resize multiple images in Python with the awesome PIL library and a small help of the os (operating system) library. By using os. listdir() function you can read all the file names in a directory. After that, all you have to do is to create a for loop to open, resize and save each image in the directory.


1 Answers

I took a quick look and fixed a few other problems along the way. Essentially my changes do this:

  • Draw the bounding box on a temporary image, set its alpha transparency, and then blit this over top of the main image.
  • Avoid extraneous drawing cycles (when the mouse isn't moving, no sense in drawing the same image again).
  • Ensure that width and height are always positive. If the rect is drawn by dragging the mouse left or up, your code would end up with a negative width and/or height, raising an exception when trying to write the final image.

Here is a screenshot of running the fixed code:

enter image description here

I split the code into two parts to avoid the scrollbars:

import pygame, sys
from PIL import Image
pygame.init()

def displayImage(screen, px, topleft, prior):
    # ensure that the rect always has positive width, height
    x, y = topleft
    width =  pygame.mouse.get_pos()[0] - topleft[0]
    height = pygame.mouse.get_pos()[1] - topleft[1]
    if width < 0:
        x += width
        width = abs(width)
    if height < 0:
        y += height
        height = abs(height)

    # eliminate redundant drawing cycles (when mouse isn't moving)
    current = x, y, width, height
    if not (width and height):
        return current
    if current == prior:
        return current

    # draw transparent box and blit it onto canvas
    screen.blit(px, px.get_rect())
    im = pygame.Surface((width, height))
    im.fill((128, 128, 128))
    pygame.draw.rect(im, (32, 32, 32), im.get_rect(), 1)
    im.set_alpha(128)
    screen.blit(im, (x, y))
    pygame.display.flip()

    # return current box extents
    return (x, y, width, height)

And part 2 (concatenate to the above):

def setup(path):
    px = pygame.image.load(path)
    screen = pygame.display.set_mode( px.get_rect()[2:] )
    screen.blit(px, px.get_rect())
    pygame.display.flip()
    return screen, px

def mainLoop(screen, px):
    topleft = bottomright = prior = None
    n=0
    while n!=1:
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONUP:
                if not topleft:
                    topleft = event.pos
                else:
                    bottomright = event.pos
                    n=1
        if topleft:
            prior = displayImage(screen, px, topleft, prior)
    return ( topleft + bottomright )

if __name__ == "__main__":
    input_loc = 'stack.png'
    output_loc = 'out.png'
    screen, px = setup(input_loc)
    left, upper, right, lower = mainLoop(screen, px)

    # ensure output rect always has positive width, height
    if right < left:
        left, right = right, left
    if lower < upper:
        lower, upper = upper, lower
    im = Image.open(input_loc)
    im = im.crop(( left, upper, right, lower))
    pygame.display.quit()
    im.save(output_loc)
like image 63
samplebias Avatar answered Oct 05 '22 02:10

samplebias