简体   繁体   English

使用 Python 进行图像裁剪

[英]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.我是 Python 编码的新手,我正在编写一个程序,我将在其中裁剪输入的图像,然后将其保存在某个位置。 Now, I am being able to do this using a combination of PIL and pygame.现在,我可以使用 PIL 和 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.但问题是,当我从打开的 pygame window 中选择图像时,选择区域完全不透明,我无法看穿我选择的区域。 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.问候。

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.在临时图像上绘制边界框,设置其 alpha 透明度,然后将其覆盖在主图像之上。
  • 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:这是运行固定代码的屏幕截图:

在此处输入图像描述

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):第 2 部分(与上述内容连接):

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)

The answer by samplebias was great for me. samplebias 的答案对我来说很棒。 I extended it for the large images I am working with by adding zoom and pan capabilities.我通过添加缩放和平移功能为我正在使用的大图像扩展了它。

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 main function samplebias provided.使用提供的主要function 样本偏差。

Thanks Stack Overflow!感谢堆栈溢出!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM