Python PyQtGraphでROIを実装する方法を説明する。
結論
pg.ROI([x原点, y原点], [x長さ, y長さ])でROIのインスタンス(下記例ではself.roi)を生成する。addPlotのインスタンス(下記例ではself.p)に.addItem(ROIのインスタンス)とする。
self.roi = pg.ROI([10, 20], [100, 200])
self.p.addItem(self.roi)
具体例
- ROIの[x原点, y原点], [x長さ, y長さ]を指定してROIを生成する。
- ユーザーがROIの位置やサイズを変化させようとしたときのx原点, y原点を整数(正確にはsnapSize(defaul=1)の整数倍)に固定する。
- ユーザーがROIのサイズを変化させようとしたときのx長さ, y長さを整数(正確にはsnapSize(defaul=1)の整数倍)に固定する。
#!/usr/bin/env python3
import sys
from PyQt6.QtWidgets import (QApplication, QWidget, QGraphicsProxyWidget,
QLabel, QCheckBox)
import pyqtgraph as pg
import numpy as np
class GuiWindow(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ウィンドウを用意する()
self.画像を準備する()
self.画像を描画する()
self.ROIを設置する()
self.文字表示板を設置する()
self.チェックボックスを設置する()
self.スペーサーを設置する()
def ウィンドウを用意する(self):
self.graph = pg.GraphicsLayoutWidget(show=True)
def 画像を準備する(self):
self.画像データ = np.random.normal(size=(500,500))
def 画像を描画する(self):
self.img = pg.ImageItem(self.画像データ)
self.p = self.graph.addPlot(row=0, col=0, rowspan=10)
self.p.addItem(self.img)
self.p.getViewBox().invertY(True)
self.p.getViewBox().setAspectLocked(True)
def ROIを設置する(self):
self.roi = pg.ROI([10, 20], [100, 200], # ? 1
translateSnap=True, # ? 2
scaleSnap=True, # ? 3
)
self.roi.setZValue(10) # make sure ROI is drawn above image
self.p.addItem(self.roi)
self.add_roi_scale_handle()
self.roi.sigRegionChangeFinished.connect(self.display_roi_info)
def roiの位置とサイズを取得する(self):
self.roi_pos_x, self.roi_pos_y = self.roi.pos()
self.roi_len_x, self.roi_len_y = self.roi.size()
def display_roi_info(self):
self.roiの位置とサイズを取得する()
self.文字表示版_値_x原点.setInnerText(str(int(self.roi_pos_x)))
self.文字表示版_値_y原点.setInnerText(str(int(self.roi_pos_y)))
self.文字表示版_値_x長さ.setInnerText(str(int(self.roi_len_x)))
self.文字表示版_値_y長さ.setInnerText(str(int(self.roi_len_y)))
roi_data = self.画像データ[int(self.roi_pos_x) : int(self.roi_pos_x + self.roi_len_x),
int(self.roi_pos_y) : int(self.roi_pos_y + self.roi_len_y)]
self.文字表示版_値_最大.setInnerText(str(int(np.max(roi_data))))
self.文字表示版_値_最小.setInnerText(str(int(np.min(roi_data))))
self.文字表示版_値_平均.setInnerText(str(int(np.mean(roi_data))))
self.文字表示版_値_偏差.setInnerText(str(int(np.std(roi_data))))
def 文字表示板を設置する(self):
self.文字表示版_項目_x原点 = FlexibleSpace(app=self, win=self.graph, row=0, col=1, w=50, h=25, text='x原点')
self.文字表示版_項目_y原点 = FlexibleSpace(app=self, win=self.graph, row=1, col=1, w=50, h=25, text='y原点')
self.文字表示版_項目_x長さ = FlexibleSpace(app=self, win=self.graph, row=2, col=1, w=50, h=25, text='x長さ')
self.文字表示版_項目_y長さ = FlexibleSpace(app=self, win=self.graph, row=3, col=1, w=50, h=25, text='y長さ')
self.文字表示版_項目_最大 = FlexibleSpace(app=self, win=self.graph, row=4, col=1, w=50, h=25, text='最大')
self.文字表示版_項目_最小 = FlexibleSpace(app=self, win=self.graph, row=5, col=1, w=50, h=25, text='最小')
self.文字表示版_項目_平均 = FlexibleSpace(app=self, win=self.graph, row=6, col=1, w=50, h=25, text='平均')
self.文字表示版_項目_偏差 = FlexibleSpace(app=self, win=self.graph, row=7, col=1, w=50, h=25, text='偏差')
self.文字表示版_値_x原点 = FlexibleSpace(app=self, win=self.graph, row=0, col=2, w=50, h=25)
self.文字表示版_値_y原点 = FlexibleSpace(app=self, win=self.graph, row=1, col=2, w=50, h=25)
self.文字表示版_値_x長さ = FlexibleSpace(app=self, win=self.graph, row=2, col=2, w=50, h=25)
self.文字表示版_値_y長さ = FlexibleSpace(app=self, win=self.graph, row=3, col=2, w=50, h=25)
self.文字表示版_値_最大 = FlexibleSpace(app=self, win=self.graph, row=4, col=2, w=50, h=25)
self.文字表示版_値_最小 = FlexibleSpace(app=self, win=self.graph, row=5, col=2, w=50, h=25)
self.文字表示版_値_平均 = FlexibleSpace(app=self, win=self.graph, row=6, col=2, w=50, h=25)
self.文字表示版_値_偏差 = FlexibleSpace(app=self, win=self.graph, row=7, col=2, w=50, h=25)
self.desplay_roi_info()
def チェックボックスを設置する(self):
self.チェックボックス = CheckReceiver(app=self, win=self.graph, row=8, col=1, colspan=2, h=25, text='ハンドル')
def スペーサーを設置する(self):
self.flexible_space = FlexibleSpace(app=self, win=self.graph, row=9, col=1, colspan=2)
def add_roi_scale_handle(self):
self.roi.addScaleHandle([0.5, 1], [0.5, 0]) #第1引数:handle位置/第2引数:伸張基準点
self.roi.addScaleHandle([1, 0.5], [0, 0.5])
self.roi.addScaleHandle([0.5, 0], [0.5, 1])
self.roi.addScaleHandle([0, 0.5], [1, 0.5])
def remove_roi_scale_handle(self):
self.roi.removeHandle(0)
self.roi.removeHandle(1)
self.roi.removeHandle(-1)
self.roi.removeHandle(-0)
class FlexibleSpace(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QLabel()
def set_style():
style = ('QLabel{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
make_object()
set_style()
set_size(w=w, h=h)
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
class CheckReceiver(QWidget):
def __init__(self, app, win, row, col, rowspan=1, colspan=1, w=0, h=0, name='', text=''):
super().__init__()
self.set_layout(win=win, row=row, col=col, rowspan=rowspan, colspan=colspan)
self.set_object(app=app, w=w, h=h, name=name, text=text)
self.set_proxy()
self.setInnerText(text=text)
def set_layout(self, win, row, col, rowspan, colspan):
self.p = win.addLayout(row=row, col=col, rowspan=rowspan, colspan=colspan)
self.p.setContentsMargins(10,0,10,0) # 左,上,右,下
def set_object(self, app, w, h, name, text):
def make_object():
self.object = QCheckBox(text)
self.object.setChecked(True)
def set_style():
style = ('QCheckBox{'
'background-color: rgba(0,0,0,0);'
'color: darkgray;'
'text-align: left;'
'}')
self.object.setStyleSheet(style)
def set_size(w, h):
def set_wsize(w):
self.object.setMinimumWidth(w)
self.object.setMaximumWidth(w)
def set_hsize(h):
self.object.setMinimumHeight(h)
self.object.setMaximumHeight(h)
if w > 0:
set_wsize(w)
else:
pass # free size
if h > 0:
set_hsize(h)
else:
pass # free size
def connect_signal_slot():
self.object.stateChanged.connect(onChanged)
def onChanged():
if self.object.isChecked():
app.add_roi_scale_handle()
else:
app.remove_roi_scale_handle()
make_object()
set_style()
set_size(w=w, h=h)
connect_signal_slot()
def set_proxy(self):
self.proxy = QGraphicsProxyWidget()
self.item = self.p.addItem(self.proxy)
self.proxy.setWidget(self.object)
def setInnerText(self, text):
self.object.setText(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = GuiWindow()
sys.exit(app.exec())
まとめ
Python PyQtGraphでROIを実装する方法を説明した。
コメント