5
4

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.

重なった矩形の和集合部分の面積を求める

Posted at

Overview

a1.png

こんな感じで、無作為に重なった矩形の、和集合部分の面積を求めたいときとかあるじゃないですか。

ほら最近流行りのこういうのとか。
(画像はこちらから拝借:https://note.nkmk.me/python-opencv-face-detection-haar-cascade/)
img

これ、補助線引いて手計算する分には気合でなんとかできるんですけど、まともに計算するとかなり大変というか
https://mathcommunication.hatenablog.com/entry/2016/10/11/003213#%E5%B9%B3%E9%9D%A2%E5%9B%B3%E5%BD%A2%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E5%8F%AF%E6%B8%AC%E6%80%A7%E3%81%A8%E9%9D%A2%E7%A9%8D

NP困難?だかなんだかで凡人には無理なので、

方針

直接描いて、ピクセルを数えます。

計算式で算出する場合みたいに綺麗な値にはならないし、解像度で誤差も出るけど、
それが問題になるケースって多分あんまりないんじゃないかと。

具体的には、

二値化して

b1.png

黒(塗りつぶし色)のピクセルを数える

opencv に countNonZero っていうまさにそれな関数があるので、コレを使う。
https://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#countnonzero

コード

じゃ、いきます。

requirements.txt
cycler==0.10.0
kiwisolver==1.2.0
matplotlib==3.2.1
numpy==1.18.4
opencv-python==4.2.0.34
Pillow==7.1.2
pyparsing==2.4.7
python-dateutil==2.8.1
six==1.14.0

ランダムなので実行するたびに矩形の位置とサイズ変わります。

a.py
from PIL import Image, ImageDraw
import numpy as np
import cv2

import random
import matplotlib


rects = [
    (random.randrange(200),
        random.randrange(200),
        random.randrange(50, 120),
        random.randrange(50, 120)
    ) for x in range(20)
]

colors = random.sample(matplotlib.colors.cnames.keys(), len(rects))

# 線画用
im1 = Image.new('RGB', (200, 200), (255, 255, 255))
d1 = ImageDraw.Draw(im1)
# 二値変換確認用
im2 = Image.new('RGB', (200, 200), (255, 255, 255))
d2 = ImageDraw.Draw(im2)

# 矩形描画
for r, c in zip(rects, colors):
    print(c, r)
    d1.rectangle(r, outline=c)
    d2.rectangle(r, fill=(0, 0, 0))

im1.save("a1.png")
im2.save("a2.png")

# 二値変換
nim = np.array(im2, dtype=np.uint8)
gim = cv2.cvtColor(nim, cv2.COLOR_RGB2GRAY)
ret, bwim = cv2.threshold(gim, 0, 255, cv2.THRESH_OTSU)

# 二値変換後の画像
cv2.imwrite("b1.png", bwim)

whitePixels = cv2.countNonZero(bwim)
blackPixels = bwim.size - whitePixels

print("-"*50)
print(whitePixels, blackPixels, bwim.size)
print("filled area rate:", blackPixels / bwim.size)

実行

bash
$ python a.py
gainsboro (188, 158, 61, 63)
palegreen (174, 182, 118, 53)
chartreuse (75, 34, 82, 81)
olive (170, 10, 93, 111)
mistyrose (183, 65, 78, 52)
indianred (25, 55, 51, 109)
mediumaquamarine (102, 155, 59, 89)
navy (169, 127, 85, 96)
darkviolet (103, 152, 76, 51)
yellowgreen (84, 6, 73, 118)
deeppink (42, 61, 95, 90)
bisque (47, 101, 107, 105)
dimgrey (95, 179, 91, 70)
maroon (146, 182, 88, 62)
whitesmoke (189, 118, 83, 112)
lavender (71, 149, 104, 117)
burlywood (36, 82, 105, 82)
darkslategrey (122, 128, 103, 52)
mediumslateblue (163, 121, 84, 92)
silver (144, 126, 61, 58)
--------------------------------------------------
18580 21420 40000
fill area rate: 0.5355

おわり。

参考

https://note.nkmk.me/python-pillow-imagedraw/
https://techtech-sorae.com/pythonopencv%E3%81%A7%E4%BA%8C%E5%80%A4%E7%94%BB%E5%83%8F%E3%81%8B%E3%82%89%E7%99%BD%E3%81%A8%E9%BB%92%E3%81%AE%E9%9D%A2%E7%A9%8D%E6%AF%94%E3%82%92%E7%AE%97%E5%87%BA/

5
4
0

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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?