2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

OpenCVとNumpyでPDF内の写真を抽出する

Last updated at Posted at 2019-05-12

以下のようなpdf内にあるカラーの写真を切り取る必要があったので、備忘録的にまとめておきます。
(なお、当方プログラミング初心者なので間違いがあれば優しく指摘していただけると助かります。。)

image.png

おおまかな流れとしては

  • 写真の四隅の座標を把握する。
  • 座標で切り取る。
    の二つだけです。

まず、必要なモジュールをインポートし、画像を読み込みます。

import cv2
import numpy as np
from PIL import Image

image = cv2.imread('pdfが置いてあるパス')

↑(訂正)imreadはpdfに対応していないようなので、pngなどに変換します。

次に読み込んだ画像をBGRからHSV空間に変換(マスク)します
写真はカラーであることから、色が付いているものを検出するためです。
今回は彩度(Satulation)の範囲を10〜255としました。

hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) 

upper = np.array([250, 255, 250])
lower = np.array([0, 10, 5])
mask = cv2.inRange(hsv, lower, upper)

次に、写真の境界を見つけていきます。
また、検出された境界に緑色の線を引いていきます。

# マスクされた画像の中から境界を見つけ、一番大きいものを保持する
(mask, cnts, hierarcy) = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
c = max(cnts, key=cv2.contourArea) 
c_sort = sorted(cnts, key=cv2.contourArea)
c2 = c_sort[-2]

# 境界を最適化する
peri = cv2.arcLength(c2, True)
approx = cv2.approxPolyDP(c2, 0.01 * peri, True)
epsilon = 0.05*cv2.arcLength(c,True)
approx = cv2.approxPolyDP(c, epsilon, True)
epsilon2 = 0.05*cv2.arcLength(c2,True)
approx2 = cv2.approxPolyDP(c2, epsilon, True)

# 境界を緑の線で描く
cv2.drawContours(image, [approx], -1, (0, 255, 0), 4)
cv2.drawContours(image, [approx2], -1, (0, 255, 0), 4)

ここで今の境界を見てみます。

cv2.imshow("Image_mask", image)

green

下の写真は四角になっていますが、上の写真は四角になっていませんでした。
そこで、四隅の座標だけ取得するため、boundingRectを使います。

x,y,w,h = cv2.boundingRect(c)
x_2 = x+w
y_2 = y+h
image = cv2.rectangle(image,(x,y),(x_2,y_2),(0,0,255),2)
x2,y2,w2,h2 = cv2.boundingRect(c2)
x2_2 = x2+w2
y2_2 = y2+h2
image = cv2.rectangle(image,(x2,y2),(x2_2,y2_2),(0,0,255),2)

これで、四隅の座標が取得できました。
あとは、これらの座標で切り取るだけです。

im = Image.open('pdfが置いてあるパス')

im_crop = im.crop((x, y, x_2, y_2))
im_crop.save('/保存する場所/保存名.png', quality=95)

im_crop = im.crop((x2, y2, x2_2, y2_2))
im_crop.save('/保存する場所/保存名.png', quality=95)

これで無事に二つの写真を抽出することができました。
image.png

image.png

背景画像にマスクした画像を合成する、というものはあったのですが、
単純に切り取る方法が見つからなかったので、残しておこうと思いました。
OpenCVの導入にはちょうどいいのかもしれません。

2
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?