#python #image-processing #python-imaging-library #crop
#python #обработка изображений #python-imaging-library #обрезка
Вопрос:
Я новичок в программировании на 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)
Любая помощь приветствуется. С уважением.
Ответ №1:
Я быстро просмотрел и исправил несколько других проблем на этом пути. По сути, мои изменения делают это:
- Нарисуйте ограничивающую рамку на временном изображении, установите его альфа-прозрачность, а затем выделите это поверх основного изображения.
- Избегайте посторонних циклов рисования (когда мышь не движется, нет смысла рисовать то же самое изображение снова).
- Убедитесь, что ширина и высота всегда положительны. Если прямоугольник рисуется перетаскиванием мыши влево или вверх, ваш код в конечном итоге будет иметь отрицательную ширину и / или высоту, вызывая исключение при попытке записать окончательное изображение.
Вот скриншот запуска исправленного кода:
Я разделил код на две части, чтобы избежать полос прокрутки:
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)
Комментарии:
1. Мне также нужна тонкая рамка вокруг прямоугольного выделения. Можете ли вы помочь мне с этим?
2. Да, вы бы использовали
pygame.draw.rect()
послеfill()
— я соответствующим образом обновил ответ.3. Сейчас я пытаюсь увеличить размер изображения на дисплее. В настоящее время дисплей pygame имеет тот же размер, что и изображение, которое я использую. Что я пытаюсь сделать, так это изменить px.get_rect (), чтобы я мог отображать изображение в увеличенном виде, чтобы, когда пользователь выбирает интересующую область, он мог сделать это более точно. Правильный ли подход?
4.для эффекта масштабирования я изменил эти две строки:
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)))
но это все еще не дает мне увеличенного изображения.5. Как я могу перетащить прямоугольник blit по экрану?
Ответ №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 )
Используйте предоставленную основную функцию samplebias.
Спасибо Stack Overflow!