Crop images using Python

I am new to Python coding and I am writing a program in which I will crop the entered image and then save it in a location. Now I can do this using a combination of PIL and pygame. But the problem is that when I select an image from the open pygame window, the selection area is completely opaque, and I cannot see through the area I select. This causes problems for my boss, who wants to see him when he chooses. 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. Best wishes.

+4
source share
2 answers

I quickly looked and fixed a few more problems. Essentially my changes do this:

  • Draw a bounding box on the temporary image, set its alpha transparency, and then close it on top of the main image.
  • Avoid extraneous drawing cycles (when the mouse does not move, it makes no sense to draw the same image again).
  • Make sure the width and height are always positive. If the rectangle is drawn by dragging the mouse left or up, your code will have a negative width and / or height, throwing an exception when trying to write the final image.

Here is a screenshot of a fixed code launch:

enter image description here

I split the code into two parts to avoid scrolling:

 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 (connect with 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) 
+9
source

The answer to samplebias was great for me. I expanded it for the large images I'm working with, adding the ability to scale and pan.

 import pygame, sys from pygame.locals import K_a, K_s,K_w,K_d,K_LEFTBRACKET,K_RIGHTBRACKET from PIL import Image pygame.init() BG_COLOR = (0,0,0) def displayRect(screen, px, topleft, prior,pos,scale): # ensure that the rect always has positive width, height #topleft = [(val-pos[i])/scale for i,val in enumerate(topleft)] topleft = [(val/scale-pos[i]) for i,val in enumerate(topleft)] x, y = topleft bottomright = pygame.mouse.get_pos() width = bottomright[0] - topleft[0] height = bottomright[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 rect = px.get_rect() px = pygame.transform.scale(px,[rect.width/scale, rect.height/scale]) screen.blit(px, (rect[0]-pos[0],rect[1]-pos[1])) 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) def setup(px): screen = pygame.display.set_mode( px.get_rect()[2:] ) screen.blit(px, px.get_rect()) pygame.display.flip() return screen, px def move(pos,scale,px,screen): x,y = pos #print pos,x rect = px.get_rect() screen.fill(BG_COLOR) px = pygame.transform.scale(px,[rect.width/scale, rect.height/scale]) screen.blit(px, (rect[0]-x,rect[1]-y)) pygame.display.flip() #px.rect.topleft = pr.rect.topleft[0] - x, def mainLoop(screen, px, filelist): topleft = bottomright = prior = None n=0 scale = 1 pos = [0,0] while n!=1: for event in pygame.event.get(): if event.type == pygame.MOUSEBUTTONUP: if not topleft: topleft = [(val+pos[i])*scale for i,val in enumerate(event.pos)] print "tr: ",topleft else: bottomright = [(val+pos[i])*scale for i,val in enumerate(event.pos)] print "br: ",bottomright n=1 if event.type == pygame.KEYDOWN and event.key == K_a: pos = [pos[0]-200,pos[1]] move(pos,scale,px,screen) if event.type == pygame.KEYDOWN and event.key == K_d: pos = [pos[0]+200,pos[1]] move(pos,scale,px,screen) if event.type == pygame.KEYDOWN and event.key == K_w: pos = [pos[0],pos[1]-200] move(pos,scale,px,screen) if event.type == pygame.KEYDOWN and event.key == K_s: pos = [pos[0],pos[1]+200] move(pos,scale,px,screen) if event.type == pygame.KEYDOWN and event.key == K_RIGHTBRACKET: scale = scale/1.25 move(pos,scale,px,screen) if event.type == pygame.KEYDOWN and event.key == K_LEFTBRACKET: scale = scale*1.25 move(pos,scale,px,screen) if topleft: prior = displayRect(screen, px, topleft, prior,pos,scale) return ( topleft + bottomright ) 

Use the basic functions of samplebias.

Thanks, stack overflow!

+1
source

All Articles