Watermark on Image

  • 이미지 도용을 방지할 수 있는 watermark를 만들어 봅시다.
  • matplotlib으로 데이터와 이미지를 동시에 표현해서 만듭니다.
  • watermark를 박는 4가지 방법을 소개합니다.

1. 다른 사람의 자료에서 내 그림이 보일 때

매일경제: 월 100장씩 사라지던 사우나 수건… 도난 막는 방법은?

  • 최근 제 블로그의 그림이 다른 데서 보이는 일을 겪었습니다.

    원본 vs 도용

  • 다행히 제게 크리티컬한 이미지가 아니었습니다.

  • 저도 데이터 시각화 교과서그림을 재현한 것이었거든요.

  • 그러나 그림을 재현한 제 그림을 가져갔다면 출처는 표시하는 것이 예의일 것입니다.

  • 다만 데이터가 한반도 월별 기온분포로 둔갑한 건은 좀 많이 불편했습니다.
  • 의도가 무엇이든 데이터를 왜곡시켰다는 점 때문입니다.
  • 그러나 누군가에겐 크게 불편한 일이 될 수도 있는 일입니다.
  • 이럴 때 사용하는 기법이 워터마크입니다.
  • 퍼가지 못하게 할 수는 없지만, 퍼가더라도 무단 도용임을 알 수 있게 한 것이죠.

이런 겁니다. (출처=매일경제)

  • matplotlib을 이용해서 그림에 워터마크를 박아 봅시다.

2. 실습 재료 준비

2.1. watermark 준비

  • 제 블로그의 파비콘을 워터마크로 사용합니다.
    192 x 192 x 4 이미지입니다.
    1
    2
    3
    4
    5
    6
    7
    # watermark image

    im_wm = plt.imread("./44_watermark_1.png")
    plt.imshow(im_wm)
    plt.grid(False)
    plt.axis(False)
    plt.show()

2.2. 예제 이미지 준비

  • iris dataset의 K-means 결과물을 준비합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from sklearn.datasets import load_iris
    from sklearn.cluster import KMeans

    # iris 데이터셋 읽기
    iris = load_iris()
    X = iris.data

    # iris dataset clustering
    kmeans = KMeans(n_clusters=3)
    cluster = kmeans.fit(X)
  • seaborn으로 간단하게 스타일링을 하고, 그림을 그립니다.

  • 클러스터링 결과물을 꽃받침과 꽃잎의 분포에 따라 그립니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 시각화 스타일링
    sns.set_style("whitegrid")
    sns.set_context("talk")

    # 객체지향 baseline
    fig, axs = plt.subplots(ncols=2, figsize=(10,5))

    axs[0].scatter(X[:,0], X[:,1], c=cluster.labels_, cmap="viridis", ec="k")
    axs[1].scatter(X[:,2], X[:,3], c=cluster.labels_, cmap="viridis", ec="k")

    axs[0].set_title("sepal width vs height", pad=12)
    axs[1].set_title("petal width vs height", pad=12)

    fig.tight_layout()


3. 이미지에 워터마크 박기

matplotlib contents: Watermark image

3.1. fig.figimage()

  • figure에 이미지를 탑재하는 방법입니다.
  • axes에 무관하게 figure 전 영역을 사용할 수 있어 가장 많이 사용합니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 1. figure watermark (default)
    fig, axs = plt.subplots(ncols=2, figsize=(10,5))

    axs[0].scatter(X[:,0], X[:,1], c=cluster.labels_, cmap="viridis", ec="k")
    axs[1].scatter(X[:,2], X[:,3], c=cluster.labels_, cmap="viridis", ec="k")

    axs[0].set_title("sepal length vs width", pad=12)
    axs[1].set_title("petal length vs width", pad=12)

    # 워터마크 삽입
    figimage = fig.figimage(im_wm, resize=False, alpha=0.1)

    fig.tight_layout()

  • 기본값으로 좌측 하단에 watermark를 생성합니다.
  • xo=, yo=인자로 offset을 설정해서 그림 중앙으로 옮겨봅니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 1. figure watermark (offset)
    fig, axs = plt.subplots(ncols=2, figsize=(10,5))

    axs[0].scatter(X[:,0], X[:,1], c=cluster.labels_, cmap="viridis", ec="k")
    axs[1].scatter(X[:,2], X[:,3], c=cluster.labels_, cmap="viridis", ec="k")

    axs[0].set_title("sepal length vs width", pad=12)
    axs[1].set_title("petal length vs width", pad=12)

    # 워터마크 이동 삽입
    figimage = fig.figimage(im_wm, xo=250, yo=80, resize=False, alpha=0.1)

    fig.tight_layout()

3.2. ax.imshow()

  • 가상의 axes를 만들고 거기에 그림을 입히는 방식입니다.
  • axes 크기로 그림 크기 조정이 가능하기 때문에 편리합니다.
  • fig.figimage()로 그림 크기를 조정하려면 다소 성가시기 때문입니다 (방법).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 2. axes watermark
    fig, axs = plt.subplots(ncols=2, figsize=(10,5))

    axs[0].scatter(X[:,0], X[:,1], c=cluster.labels_, cmap="viridis", ec="k")
    axs[1].scatter(X[:,2], X[:,3], c=cluster.labels_, cmap="viridis", ec="k")

    axs[0].set_title("sepal length vs width", pad=12)
    axs[1].set_title("petal length vs width", pad=12)

    # 워터마크 삽입
    ax_watermark = fig.add_axes([0.25, 0.25, 0.5, 0.5])
    ax_watermark.imshow(im_wm, alpha=0.1)
    ax_watermark.grid(False)
    ax_watermark.axis(False)

    fig.tight_layout()

3.3. ax.add_artist()

  • 이미지 객체를 갖다 붙이는 방식입니다.
  • 이렇게 설명하면 가장 직관적인데,
    (1) 이미지를 지정하고 OffsetImage,
    (2) 위치를 지정하고 AnnotationBbox,
    (3) 붙이는 add_artist() 과정이 번거로운 것도 사실입니다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    from matplotlib.offsetbox import OffsetImage, AnnotationBbox

    fig, axs = plt.subplots(ncols=2, figsize=(10,5))

    axs[0].scatter(X[:,0], X[:,1], c=cluster.labels_, cmap="viridis", ec="k")
    axs[1].scatter(X[:,2], X[:,3], c=cluster.labels_, cmap="viridis", ec="k")

    axs[0].set_title("sepal length vs width", pad=12)
    axs[1].set_title("petal length vs width", pad=12)

    # 워터마크 삽입
    oi = OffsetImage(im_wm, zoom = 1, alpha=0.1)
    box0 = AnnotationBbox(oi, (6, 3.25), frameon=False)
    axs[0].add_artist(box0)

    box1 = AnnotationBbox(oi, (4, 1.25), frameon=False)
    axs[1].add_artist(box1)

    fig.tight_layout()

  • 이 방식은 axes에 삽입하기 때문에, axes를 벗어나면 잘 안됩니다.

  • 위 코드에서 워터마크 삽입 부분을 고치면 이렇게 됩니다.

    1
    2
    3
    4
    5
    6
    oi = OffsetImage(im_wm, zoom = 1, alpha=0.1)
    box0 = AnnotationBbox(oi, (8, 3.25), frameon=False)
    axs[0].add_artist(box0)

    box1 = AnnotationBbox(oi, (1, 2.5), frameon=False)
    axs[1].add_artist(box1)


  • 순서상 왼쪽 axes 위에 오른쪽 axes가 있습니다.
    왼쪽 워터마크가 오른쪽 axes에 가립니다.
    오른쪽 워터마크는 왼쪽 axes를 덮을 수 있습니다.

  • 좌표를 조금씩 옮기다 워터마크가 사라지기도 합니다.

    1
    2
    3
    4
    5
    6
    oi = OffsetImage(im_wm, zoom = 1, alpha=0.1)
    box0 = AnnotationBbox(oi, (8.2, 3.25), frameon=False)
    axs[0].add_artist(box0)

    box1 = AnnotationBbox(oi, (0.6, 2.5), frameon=False)
    axs[1].add_artist(box1)


※ 보호받고 싶은 이미지가 있을 때 적절히 사용하시기 바랍니다.


도움이 되셨나요? 카페인을 투입하시면 다음 포스팅으로 변환됩니다

Share