【问题标题】:Image Cropping using Python使用 Python 进行图像裁剪
【发布时间】:2011-09-02 10:56:47
【问题描述】:

我是 Python 编码的新手,我正在编写一个程序,我将在其中裁剪输入的图像,然后将其保存在某个位置。现在,我可以使用 PIL 和 pygame 的组合来做到这一点。但问题是,当我从打开的 pygame 窗口中选择图像时,选择区域完全不透明,我无法看穿我选择的区域。这给我的老板带来了问题,他希望能够在他选择的时候看穿它。为了让你们更好地理解这个问题,我在这里写我的代码:

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)

感谢任何帮助。问候。

【问题讨论】:

    标签: python image-processing python-imaging-library crop


    【解决方案1】:

    我快速浏览了一下,并在此过程中修复了一些其他问题。基本上我的更改是这样做的:

    • 在临时图像上绘制边界框,设置其 alpha 透明度,然后在主图像上方进行 blit。
    • 避免无关的绘图循环(当鼠标不移动时,再次绘制相同的图像毫无意义)。
    • 确保宽度和高度始终为正值。如果通过向左或向上拖动鼠标来绘制矩形,您的代码将以负的宽度和/或高度结束,从而在尝试编写最终图像时引发异常。

    下面是运行固定代码的截图:

    我将代码分成两部分以避免滚动条:

    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)
    

    和第 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)
    

    【讨论】:

    • 感谢兄弟的及时帮助。问候。
    • 我还需要矩形选区周围的细边框。你能帮我解决这个问题吗?
    • 是的,你会在fill() 之后使用pygame.draw.rect() - 我已经相应地更新了答案。
    • 我现在正在尝试增加图像的显示尺寸。目前,pygame 显示与我使用的图片大小相同。我想要做的是篡改 px.get_rect() 以便我可以在缩放条件下显示图像,以便当用户选择感兴趣的区域时,他可以更准确地做到这一点。方法正确吗?
    • 对于缩放效果,我更改了这两行:screen = pygame.display.set_mode((int(px.get_rect()[2]*1.2),int(px.get_rect()[3]*1.2))) screen.blit(px,(px.get_rect()[0],px.get_rect()[1],int(px.get_rect()[2]*1.2),int(px.get_rect()[3]*1.2))) 但它仍然没有给我一个缩放的图像。
    【解决方案2】:

    samplebias 的答案对我来说很棒。我通过添加缩放和平移功能为我正在使用的大图像扩展了它。

    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 )
    

    使用提供的 ma​​in 函数 samplebias。

    感谢堆栈溢出!

    【讨论】:

      猜你喜欢
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 2013-12-20
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      相关资源
      最近更新 更多