- 이미지 도용을 방지할 수 있는 watermark를 만들어 봅시다.
- matplotlib으로 데이터와 이미지를 동시에 표현해서 만듭니다.
- watermark를 박는 4가지 방법을 소개합니다.
1. 다른 사람의 자료에서 내 그림이 보일 때
최근 제 블로그의 그림이 다른 데서 보이는 일을 겪었습니다.
다행히 제게 크리티컬한 이미지가 아니었습니다.
저도 데이터 시각화 교과서의 그림을 재현한 것이었거든요.
그러나 그림을 재현한 제 그림을 가져갔다면 출처는 표시하는 것이 예의일 것입니다.
- 다만 데이터가 한반도 월별 기온분포로 둔갑한 건은 좀 많이 불편했습니다.
- 의도가 무엇이든 데이터를 왜곡시켰다는 점 때문입니다.
- 그러나 누군가에겐 크게 불편한 일이 될 수도 있는 일입니다.
- 이럴 때 사용하는 기법이 워터마크입니다.
- 퍼가지 못하게 할 수는 없지만, 퍼가더라도 무단 도용임을 알 수 있게 한 것이죠.
- 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
10from 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. 이미지에 워터마크 박기
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
19from 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
6oi = 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
6oi = 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)
※ 보호받고 싶은 이미지가 있을 때 적절히 사용하시기 바랍니다.