tohokuaikiのチラシの裏

技術的ネタとか。

Pythonで画像のトリミングをいい感じでやってくれる(CentOS8)

この記事を見てやってみようと思いました。

環境

こんな感じ。

[root@centos8 ~]# cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
[root@centos8 ~]# which python3.6
/usr/bin/python3.6
[root@centos8 ~]# which pip3.6
/usr/local/bin/pip3.6

とりあえず、環境設定

[vagrant@centos8 ~]$ pip3.6 install opencv-python
Collecting opencv-python
  Downloading https://files.pythonhosted.org/packages/38/a9/cd39fd25df434b5d9451dc266c12b72f68282a2b9bd5d7b4aa2d57d6c20e/opencv-python-4.4.0.44.tar.gz (88.9MB)
    100% |=====================| 88.9MB 16kB/s
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-85w38wrx/opencv-python/setup.py", line 9, in <module>
        import skbuild
    ModuleNotFoundError: No module named 'skbuild'

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-85w38wrx/opencv-python/

となってコケる… こちらを見るとpip自体が古いみたい。

$ sudo su -
[root@centos8 ~]# pip3.6 install -U pip
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3.6 install --user` instead.
Collecting pip
  Downloading https://files.pythonhosted.org/packages/4e/5f/528232275f6509b1fff703c9280e58951a81abe24640905de621c9f81839/pip-20.2.3-py2.py3-none-any.whl (1.5MB)
    100% |=====================| 1.5MB 904kB/s
Installing collected packages: pip
Successfully installed pip-20.2.3

[root@centos8 ~]# logout
[vagrant@centos8 ~]$ pip3.6 install opencv-python
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Defaulting to user installation because normal site-packages is not writeable
Collecting opencv-python
  Downloading opencv_python-4.4.0.44-cp36-cp36m-manylinux2014_x86_64.whl (49.5 MB)
     |=====================| 49.5 MB 498 kB/s
Collecting numpy>=1.13.3
  Downloading numpy-1.19.2-cp36-cp36m-manylinux2010_x86_64.whl (14.5 MB)
     |=====================| 14.5 MB 12.9 MB/s
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.19.2 opencv-python-4.4.0.44

インストールできた。

プログラムを動かしてみる

Pythonはほとんどやったことありません。

とりあえず、コピペしてみる。

import cv2
import numpy as np

from IPython.display import display, Image

def display_cv_image(image, format='.png'):
    decoded_bytes = cv2.imencode(format, image)[1].tobytes()
    display(Image(data=decoded_bytes))

img = cv2.imread("適当な画像.jpg")
display_cv_image(img)

# グレイスケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二値化
ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY)
display_cv_image(th1)

おもむろに、

$ python3.6 opencv_test.py

してみると

ModuleNotFoundError: No module named 'IPython'

なるほど…ipython(全く知らない)が必要っぽいな…ということで

$ pip3.6 install ipython

すると、何やらインストールした。この後で $ python3.6 opencv_test.py すると動いた。

display_cv_image()ってなんやねん…

これ、バイナリを出力してくれるのかと思ったけど、なんか違う。リダイレクトさせても

<IPython.core.display.Image object>

としか出ない…うーん。

とりあえずファイルに出力する

display_cv_imageというのがイマイチ良くわからないけど、とりあえずこんな感じでファイルに出力するだけにする。

def display_cv_image(image, output='output.jpg'):
     cv2.imwrite(output, image)

先ほどのエントリのコードを

import cv2
import numpy as np

from IPython.display import display, Image

def display_cv_image(image, output='output.jpg'):
     cv2.imwrite(output, image)
#    decoded_bytes = cv2.imencode(format, image)[1].tobytes()
#    display(Image(data=decoded_bytes))

img = cv2.imread("IMG_8270.jpg")
# display_cv_image(img)

# グレイスケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 二値化
ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY)
display_cv_image(th1)

すると動いた。やった。

輪郭検出

エントリの

# 二値化
ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY)
display_cv_image(th1)

image, contours, hierarchy = cv2.findContours(th1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 面積の大きいもののみ選別
areas = []
for cnt in contours:
    area = cv2.contourArea(cnt)
    if area > 10000:
        epsilon = 0.1*cv2.arcLength(cnt,True)
        approx = cv2.approxPolyDP(cnt,epsilon,True)
        areas.append(approx)

cv2.drawContours(img,areas,-1,(0,255,0),3)
display_cv_image(img)

をすると、エラーが出た。

got 2)
[vagrant@centos8 opencv]$ python3.6 trimming.py
Traceback (most recent call last):
  File "trimming.py", line 22, in <module>
    image, contours, hierarchy = cv2.findContours(th1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
ValueError: not enough values to unpack (expected 3, got 2)

にある「opencvの最新版であるOpenCV4では、」ということで

[vagrant@centos8 opencv]$ pip3.6 show opencv-python
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with '-m pip' instead of running pip directly.
Name: opencv-python
Version: 4.4.0.44
Summary: Wrapper package for OpenCV python bindings.
Home-page: https://github.com/skvark/opencv-python
Author: None
Author-email: None
License: MIT
Location: /home/vagrant/.local/lib/python3.6/site-packages
Requires: numpy
Required-by:

4.4.0.44だった。ということで、

image, contours, hierarchy = cv2.findContours(th1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

contours, hierarchy = cv2.findContours(th1, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

にして動いた。