Обрезка изображения с использованием Python

Я новичок в программировании на 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)

Любая помощь приветствуется. С Уважением.


person Arnab Ghosal    schedule 26.05.2011    source источник


Ответы (2)


Я быстро посмотрел и исправил еще несколько проблем. По сути, мои изменения делают это:

  • Нарисуйте ограничивающий прямоугольник на временном изображении, установите его альфа-прозрачность, а затем скопируйте его поверх основного изображения.
  • Избегайте лишних циклов рисования (когда мышь не двигается, нет смысла снова рисовать то же изображение).
  • Убедитесь, что ширина и высота всегда положительны. Если прямоугольник нарисован путем перетаскивания мыши влево или вверх, ваш код будет иметь отрицательную ширину и / или высоту, что вызовет исключение при попытке записать окончательное изображение.

Вот скриншот выполнения исправленного кода:

введите описание изображения здесь

Я разделил код на две части, чтобы избежать полос прокрутки:

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)
person samplebias    schedule 26.05.2011
comment
Спасибо братан за своевременную помощь. С Уважением. - person Arnab Ghosal; 26.05.2011
comment
Мне также нужна тонкая рамка вокруг прямоугольного выделения. Вы можете мне с этим помочь? - person Arnab Ghosal; 27.05.2011
comment
Да, вы должны использовать pygame.draw.rect() после fill() - я соответствующим образом обновил ответ. - person samplebias; 27.05.2011
comment
Сейчас я пытаюсь увеличить размер отображения изображения. В настоящее время дисплей pygame имеет тот же размер, что и изображение, которое я использую. Что я пытаюсь сделать, так это вмешаться в px.get_rect (), чтобы я мог отображать изображение в увеличенном виде, чтобы, когда пользователь выбирает интересующую область, он мог сделать это более точно. Подход правильный? - person Arnab Ghosal; 28.05.2011
comment
для эффекта масштабирования я изменил эти две строки: 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))), но это все еще не дает мне увеличенного изображения. - person Arnab Ghosal; 28.05.2011

Ответ от 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 )

Используйте предоставленную основную функцию смещения выборки.

Спасибо, переполнение стека!

person Permafacture    schedule 02.01.2012