복붙노트

[PYTHON] PIL 색상을 대체하는 가장 좋은 방법은 무엇입니까?

PYTHON

PIL 색상을 대체하는 가장 좋은 방법은 무엇입니까?

나는 내 이미지에서 특정 색상을 제거하려고하지만 그것은 내가 바라던대로 잘 작동하지 않습니다. PIL을 사용하여 모든 흰색 픽셀을 투명하게 만들려고 여기에서 보았던 것과 똑같은 것을 시도 했습니까? 그러나 이미지 품질은 약간 손실이 많으므로 제거 된 부분 주변에 홀수 컬러 픽셀의 유령이 남습니다. 세 가지 값이 모두 100 미만이면 픽셀 변경과 같은 작업을 시도했지만 이미지 품질이 좋지 않았기 때문에 주변 픽셀도 검정색이 아니 었습니다.

Python의 PIL을 사용하여 색상과 그 주위를 대체하는 더 좋은 방법을 알고 있습니까? 이것은 아마도 객체를 완전히 제거하는 것을 생각할 수있는 유일한 확실한 화재 방법 일 수 있습니다. 그러나 이것을 수행하는 방법을 생각할 수는 없습니다.

그림은 흰색 바탕에 검정색 텍스트가 있습니다. 그냥 유물을 남기지 않고 이미지에서 텍스트를 완전히 제거하고 싶다고합시다.

누군가의 도움에 정말 감사 할 것입니다! 감사

해결법

  1. ==============================

    1.이미지를 2 차원 배열로 표현해야합니다. 이는 픽셀 목록의 목록을 만들거나 영리한 수학으로 1 차원 배열을 2 차원으로 보는 것을 의미합니다. 그런 다음 타겟팅 된 각 픽셀에 대해 주변 픽셀을 모두 찾아야합니다. 파이썬 생성기로 이렇게 할 수 있습니다 :

    이미지를 2 차원 배열로 표현해야합니다. 이는 픽셀 목록의 목록을 만들거나 영리한 수학으로 1 차원 배열을 2 차원으로 보는 것을 의미합니다. 그런 다음 타겟팅 된 각 픽셀에 대해 주변 픽셀을 모두 찾아야합니다. 파이썬 생성기로 이렇게 할 수 있습니다 :

    def targets(x,y):
        yield (x,y) # Center
        yield (x+1,y) # Left
        yield (x-1,y) # Right
        yield (x,y+1) # Above
        yield (x,y-1) # Below
        yield (x+1,y+1) # Above and to the right
        yield (x+1,y-1) # Below and to the right
        yield (x-1,y+1) # Above and to the left
        yield (x-1,y-1) # Below and to the left
    

    따라서 다음과 같이 사용하십시오.

    for x in range(width):
        for y in range(height):
            px = pixels[x][y]
            if px[0] == 255 and px[1] == 255 and px[2] == 255:
                for i,j in targets(x,y):
                    newpixels[i][j] = replacementColor
    
  2. ==============================

    2.가장 좋은 방법은 Gimp에서 사용 된 "alpha to color"알고리즘을 사용하여 색상을 대체하는 것입니다. 그것은 당신의 경우에 완벽하게 작동합니다. 오픈 소스 python photo processor phatch에 PIL을 사용하여이 알고리즘을 다시 구현했습니다. 여기서 전체 구현을 찾을 수 있습니다. 이것은 순수한 PIL 구현이며 다른 의존성을 가지고 있지 않습니다. 기능 코드를 복사하여 사용할 수 있습니다. 다음은 Gimp를 사용하는 샘플입니다.

    가장 좋은 방법은 Gimp에서 사용 된 "alpha to color"알고리즘을 사용하여 색상을 대체하는 것입니다. 그것은 당신의 경우에 완벽하게 작동합니다. 오픈 소스 python photo processor phatch에 PIL을 사용하여이 알고리즘을 다시 구현했습니다. 여기서 전체 구현을 찾을 수 있습니다. 이것은 순수한 PIL 구현이며 다른 의존성을 가지고 있지 않습니다. 기능 코드를 복사하여 사용할 수 있습니다. 다음은 Gimp를 사용하는 샘플입니다.

    검정색을 색상으로 사용하여 이미지에 color_to_alpha 함수를 적용 할 수 있습니다. 그런 다음 교체를 수행 할 이미지를 다른 배경색에 붙여 넣으십시오.

    그런데이 구현은 PIL에서 ImageMath 모듈을 사용합니다. getdata를 사용하여 픽셀에 액세스하는 것보다 훨씬 효율적입니다.

    편집 : 여기에 전체 코드입니다 :

    from PIL import Image, ImageMath
    
    def difference1(source, color):
        """When source is bigger than color"""
        return (source - color) / (255.0 - color)
    
    def difference2(source, color):
        """When color is bigger than source"""
        return (color - source) / color
    
    
    def color_to_alpha(image, color=None):
        image = image.convert('RGBA')
        width, height = image.size
    
        color = map(float, color)
        img_bands = [band.convert("F") for band in image.split()]
    
        # Find the maximum difference rate between source and color. I had to use two
        # difference functions because ImageMath.eval only evaluates the expression
        # once.
        alpha = ImageMath.eval(
            """float(
                max(
                    max(
                        max(
                            difference1(red_band, cred_band),
                            difference1(green_band, cgreen_band)
                        ),
                        difference1(blue_band, cblue_band)
                    ),
                    max(
                        max(
                            difference2(red_band, cred_band),
                            difference2(green_band, cgreen_band)
                        ),
                        difference2(blue_band, cblue_band)
                    )
                )
            )""",
            difference1=difference1,
            difference2=difference2,
            red_band = img_bands[0],
            green_band = img_bands[1],
            blue_band = img_bands[2],
            cred_band = color[0],
            cgreen_band = color[1],
            cblue_band = color[2]
        )
    
        # Calculate the new image colors after the removal of the selected color
        new_bands = [
            ImageMath.eval(
                "convert((image - color) / alpha + color, 'L')",
                image = img_bands[i],
                color = color[i],
                alpha = alpha
            )
            for i in xrange(3)
        ]
    
        # Add the new alpha band
        new_bands.append(ImageMath.eval(
            "convert(alpha_band * alpha, 'L')",
            alpha = alpha,
            alpha_band = img_bands[3]
        ))
    
        return Image.merge('RGBA', new_bands)
    
    image = color_to_alpha(image, (0, 0, 0, 255))
    background = Image.new('RGB', image.size, (255, 255, 255))
    background.paste(image.convert('RGB'), mask=image)
    
  3. ==============================

    3.numpy 및 PIL 사용 :

    numpy 및 PIL 사용 :

    그러면 이미지가 모양이 매끄러운 배열 (W, H, 3)로로드됩니다. 여기서 W는 너비와 높이가 높이입니다. 배열의 세 번째 축은 3 색을 나타냅니다. 채널, R, G, B.

    import Image
    import numpy as np
    
    orig_color = (255,255,255)
    replacement_color = (0,0,0)
    img = Image.open(filename).convert('RGB')
    data = np.array(img)
    data[(data == orig_color).all(axis = -1)] = replacement_color
    img2 = Image.fromarray(data, mode='RGB')
    img2.show()
    

    orig_color는 길이가 3 인 튜플이며 데이터에는 모양 (W, H, 3), NumPy 방송 orig_color를 셰이프 배열 (W, H, 3)에 대입하여 비교 데이터를 수행합니다. == orig_color. 그 결과 모양의 부울 배열 (W, H, 3)이됩니다.

    (data == orig_color) .all (축 = -1)은 모양의 부울 배열입니다 (W, H). 데이터의 RGB 색상이 original_color 인 모든 경우 True입니다.

  4. ==============================

    4.

    #!/usr/bin/python
    from PIL import Image
    import sys
    
    img = Image.open(sys.argv[1])
    img = img.convert("RGBA")
    
    pixdata = img.load()
    
    # Clean the background noise, if color != white, then set to black.
    # change with your color
    for y in xrange(img.size[1]):
        for x in xrange(img.size[0]):
            if pixdata[x, y] == (255, 255, 255, 255):
                pixdata[x, y] = (0, 0, 0, 255)
    
  5. ==============================

    5.픽셀을 쉽게 식별 할 수없는 경우 (예 : r <100, g <100 및 b <100)도 검은 색 영역과 정확하게 일치하지 않으면 노이즈가 많음을 의미합니다.

    픽셀을 쉽게 식별 할 수없는 경우 (예 : r <100, g <100 및 b <100)도 검은 색 영역과 정확하게 일치하지 않으면 노이즈가 많음을 의미합니다.

    가장 좋은 방법은 지역을 식별하고 원하는 색상으로 채우는 것입니다. 수동으로 지역을 식별하거나 가장자리 감지 등으로 할 수 있습니다. http://bitecode.co.uk/2008/07/edge-detection-in-python/

    또는 더 정교한 접근법은 객체를 식별하기 위해 opencv (http://opencv.willowgarage.com/wiki/)와 같은 라이브러리를 사용하는 것입니다.

  6. ==============================

    6.이것은 내 코드의 일부이며 결과는 다음과 같습니다. 출처

    이것은 내 코드의 일부이며 결과는 다음과 같습니다. 출처

    목표

    import os
    import struct
    from PIL import Image
    def changePNGColor(sourceFile, fromRgb, toRgb, deltaRank = 10):
        fromRgb = fromRgb.replace('#', '')
        toRgb = toRgb.replace('#', '')
    
        fromColor = struct.unpack('BBB', bytes.fromhex(fromRgb))
        toColor = struct.unpack('BBB', bytes.fromhex(toRgb))
    
        img = Image.open(sourceFile)
        img = img.convert("RGBA")
        pixdata = img.load()
    
        for x in range(0, img.size[0]):
            for y in range(0, img.size[1]):
                rdelta = pixdata[x, y][0] - fromColor[0]
                gdelta = pixdata[x, y][0] - fromColor[0]
                bdelta = pixdata[x, y][0] - fromColor[0]
                if abs(rdelta) <= deltaRank and abs(gdelta) <= deltaRank and abs(bdelta) <= deltaRank:
                    pixdata[x, y] = (toColor[0] + rdelta, toColor[1] + gdelta, toColor[2] + bdelta, pixdata[x, y][3])
    
        img.save(os.path.dirname(sourceFile) + os.sep + "changeColor" + os.path.splitext(sourceFile)[1])
    
    if __name__ == '__main__':
        changePNGColor("./ok_1.png", "#000000", "#ff0000")
    
  7. from https://stackoverflow.com/questions/1616767/pil-best-way-to-replace-color by cc-by-sa and MIT license