2026年2月16日月曜日

shapelyの図形を特定の大きさと解像度の画像に描画する


背景

shapelyで扱う図形を特定のピクセル数の画像として描画が必要な場面があったので、方法を把握しました。
備忘録として記事に残します。

使ったもの

python 3.10.12
shapely 2.0.6
matplotlib 3.10.0

プログラム解説

全体像を共有して要所を解説します。
図形は以前の記事( pythonで2次元の領域を扱うのにshapelyが便利だった )からの流用です。
画像の大きさ指定方法は下記のサイトを参考にしました。
How to create a figure with no axes ( frameless ) or labels using matplotlib ?

#!/usr/bin/python

import os
from shapely import Polygon, Point
import matplotlib.pyplot as plt

# import numpy as np
# import cv2

dir_output = os.path.join(os.path.dirname(__file__), "output")
os.makedirs(dir_output, exist_ok=True)

width = 320
height = 240
dpi = 200

fig = plt.figure(figsize=(width/dpi, height/dpi), dpi=dpi)
fig.canvas.manager.set_window_title("%dx%d %ddpi" % (width, height, dpi))

ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)

arrPoligon = [
Polygon([(36.17615365206663, 139.29274439262977),
(36.176069213304274, 139.29292611226978),
(36.17615744098333, 139.29299383803968),
(36.17625487020672, 139.2928342466215)]),
Polygon([(36.17610006593953, 139.29270885336436),
(36.17600209524877, 139.29289124355657),
(36.17592306907745, 139.29284095214328),
(36.17603565428372, 139.29261698771606)]),
]

arrPoint = [
Point(36.17614534102644, 139.29286477985536),
Point(36.17608958979661, 139.2928252172769),
Point(36.17601110498835, 139.29275883261136),
]

for polygon in arrPoligon:
# plt.fill(*polygon.exterior.xy, color="green")
plt.plot(*polygon.exterior.xy, color="green")

for point in arrPoint:
isPointInSomePolygon = False
for polygon in arrPoligon:
if polygon.contains(point):
print("%s contains %s" % (polygon, point))
isPointInSomePolygon = True
break
plt.scatter(*point.xy, color= "orange" if isPointInSomePolygon else "black")

fig.savefig(os.path.join(dir_output, "output.png"), dpi=dpi)
plt.plot()
plt.show()
上記のプログラムを実行するとpatplotlibの処理で下記の画像が表示されます。


生成されるpng画像はこちらです。


figureで大きさと解像度を指定

描画する画像の幅、高さ、解像度をfigure関数に渡して描画領域を定義後に描画処理を行うと、指定された寸法で図形が描画されます。
このプログラムでは320x240の領域に描画しています。
width = 320
height = 240
dpi = 200

fig = plt.figure(figsize=(width/dpi, height/dpi), dpi=dpi)

figureのx軸とy軸を非表示化

今回はx軸とy軸が不要だったので非表示にしました。
非表示にしたaxesをfigureに渡すと非表示になります。
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)

dpiが大きいほうが点や線が太くなる

dpiが大きいと点や線が太くなり、小さいと細くなります。

50dpi


300dpi


てっきりdpiが小さい方がドットが荒くなって点や線が太くなるのかと思っていましたが、逆でした。

figureを生成物として処理

このプログラムではfigureからpng画像を生成しています。
fig.savefig(os.path.join(dir_output, "output.png"), dpi=dpi)

figureの情報を変換することで、opencvやPILへの情報受け渡しも可能なようです。
PythonのMatplotlibのグラフをNumPy行列に変換してOpenCVやPillowで使う
matplotlibの画像からPIL画像を取得する

おわり

shapelyで扱う図形の生成画面の寸法を指定して期待通りに図示できました。

参考

How to create a figure with no axes ( frameless ) or labels using matplotlib ?

0 件のコメント :