Crop image, change black area if not not enough ph

2019-07-11 00:14发布

I have to crop a photo with python using PIL.
If the photo region is not enough, the rest of the area is colored in black.
How can I make that area white?

This is a part of the code I`m using now:

i = Image.open(filepath)
box2 = (newX,newY,newX+newW,newY+newH)
i2=i.crop(box=box2)
i2.load()
...
i2.save(new_filepath)
...
white=(255,255,255)
i3 = Image.new( 'RGB' , i2.size , white )
i3.paste( i2)
i3.save(filepath2,'PNG')

The crop works fine, but I want white instead of black in the rest of the area. I tried creating a new image with white background and pasting the croped image, but it didn`t work.

EDIT: example output

example output

EDIT2: I have the original image and the coords for the croping
I updated the code
Remeber that the crop coords can be negative.

Input & output example
input img: http://i.imgur.com/vbmPy.jpg

box2=(-743, 803, 1646, 4307)  

output img: http://i.imgur.com/K7sil.jpg

4条回答
Evening l夕情丶
2楼-- · 2019-07-11 00:14

To do exactly as you asked, convert the image to a numpy array and filter the full black rows and cols (on a second image). You can't simply make all the black pixels white, as this would affect those on the inside of the image.

import numpy
from PIL import Image
img = Image.open("hHncu.png") # Imgur's naming scheme
pix = numpy.array(img)        # Convert to array

black = numpy.array([0,0,0,255])
white = numpy.array([255,255,255,255])

pix2 = pix.copy()
dim  = pix.shape

for n in xrange(dim[0]):
    if (pix[n,:]==black).all(): 
        pix2[n,:,numpy.newaxis] = white

for n in xrange(dim[1]):
    if (pix[:,n]==black).all(): 
        pix2[:,n,numpy.newaxis] = white

# View the results
from pylab import *
subplot(121); imshow(pix )
subplot(122); imshow(pix2)
show()

enter image description here

It looks like there is some smoothing between the black and the image, a more advanced filter would be needed to fix this - but you can see how to get started from here!

查看更多
Deceive 欺骗
3楼-- · 2019-07-11 00:26

ok. so here's a quick stab at the idea i mentioned.

the rebox() function returns a 'fixed' bounding box, along with some offset data

this works in most situations. i didn't integrate the offset data , but some version of it it would probably go in the i3.paste section.

the test image, grid.png is 300x300 and has blue lines at 50px, red lines at 150px and green lines at 200px.

you should be able to tweak this to your exact needs.

enter image description here

import Image
i1 = Image.open('grid.png')


DEBUG = True

def rebox( box_original , box_crop_desired ):

    box_crop_new= list( box_crop_desired )
    box_crop_offset = [ 0 , 0 ]

    if box_crop_desired[0] < 0:
        box_crop_new[0] = 0
        box_crop_offset[0] = box_crop_desired[0]

    if box_crop_desired[1] < 0:
        box_crop_new[1] = 0
        box_crop_offset[1] = box_crop_desired[1]

    if box_crop_desired[2] > box_original[2]:
        box_crop_new[2] = box_original[2]

    if box_crop_desired[3] > box_original[3]:
        box_crop_new[3] = box_original[3]

    box_crop_offset = tuple(box_crop_offset)
    box_crop_new = tuple(box_crop_new)

    if DEBUG :
        print "box_original                      %s" % str(box_original)
        print "box_crop_offset                   %s" % str(box_crop_offset)
        print "box_crop_desired                  %s" % str(box_crop_desired)
        print "box_crop_new                      %s" % str(box_crop_new)

    return ( box_crop_new , box_crop_offset )


( newX , newY ) = ( 200 , 200 )
( newW , newH ) = ( 400 , 400 )
box_crop_desired = ( newX , newY , newX+newW, newY+newH )
( box_crop , box_crop_offset ) = rebox( i1.getbbox() , box_crop_desired )

i2 = i1.crop(box=box_crop)
i2.save('grid-out-b.png')

i3 = Image.new( 'RGBA' , ( newW , newH ) , (255,255,255) )
i3.paste( i2 , (0,0) )
i3.save('grid-out-final-b.png')
查看更多
一夜七次
4楼-- · 2019-07-11 00:27

If you can use numpy, you could do something like:

i22 = flipud(asarray(i2).copy())
# calculate the area that its black, using the original size and the box information
for i in xrange(blackrows):
  i22[i:] = asarray([255,255,255])
# and and something like that to the blackcolumns

I don't use PIL a lot, but it probably has some pixel acessing functions.

查看更多
小情绪 Triste *
5楼-- · 2019-07-11 00:30

It looks to me like you're doing something wrong, and that you should share your entire code, and the image.

I've done this many times in PIL , and the easiest solutions has always been to Paste the Crop onto an all-white image.

import Image

# open source
i = Image.open('hHncu.png')

# crop it
( newX , newY ) = ( 110 , 0 )
( newW , newH ) = ( 110 , 150 )
box_crop = ( newX,newY,newX+newW,newY+newH )
i2 = i.crop(box=box_crop)
i2.load()

# save it , just for testing
i2.save('hHncu-out.png')

# create the new image, and paste it in
# note that we're making it 300x300  and have the background set to white (255x3)
i3 = Image.new( 'RGB' , (300,300) , (255,255,255) )
# paste it at an offset. if you put no offset or a box, i3 must match i2s dimensions
i3.paste( i2 , (25,25) )
# save it
i3.save('hHncu-out-2.png')
查看更多
登录 后发表回答