Source code for arthropod_describer.tools.contour_features

import typing
from typing import List, Optional, Any

import numpy as np
import scipy.linalg
import scipy.ndimage
from sklearn.decomposition import PCA
from PySide2.QtCore import QPoint, QObject
from PySide2.QtGui import QColor, QPen
from skimage import io
from skimage.morphology import binary_erosion
import skimage.transform

from arthropod_describer.common.label_image import LabelImg
from arthropod_describer.common.state import State
from arthropod_describer.common.tool import Tool, PaintCommand, line_command


[docs]class Too_Contour(Tool): def __init__(self, state: State, parent: QObject = None): super().__init__(state, parent) self.state: State = state self._viz_active: bool = False self._viz_commands: List[PaintCommand] = [] @property def tool_name(self) -> str: return 'Contour impl.' @property def viz_active(self) -> bool: return self._viz_active
[docs] def viz_left_press(self, pos: QPoint) -> List[PaintCommand]: self._viz_active = True return []
[docs] def viz_left_release(self, pos: QPoint) -> List[PaintCommand]: lbl_img: LabelImg = self.state.current_photo[self.state.current_label_name] level_lab = lbl_img[self.state.current_label_level] picked_label = level_lab[pos.y(), pos.x()] region = lbl_img.mask_for(picked_label) pixels = np.argwhere(region) top, left = np.min(pixels[:,0]), np.min(pixels[:,1]) bottom, right = np.max(pixels[:,0]), np.max(pixels[:,1]) roi = region[top:bottom+1, left:right+1] pixels = pixels - np.array([top, left]) yy, xx = np.nonzero(roi) io.imsave('C:\\Users\\radoslav\\Desktop\\region.png', roi) io.imsave('C:\\Users\\radoslav\\Desktop\\outline.png', np.logical_xor(roi, binary_erosion(roi, footprint=np.ones((3, 3))))) x_c, y_c = round(np.mean(xx)), round(np.mean(yy)) pen = QPen(QColor(0, 255, 125)) pen.setWidthF(1.5) pca = PCA(n_components=1) pca.fit(pixels) print(f'mean is {pca.mean_}') print(f'centroid is {y_c, x_c}') next_pixel = np.array([y_c + top, x_c + left]) + 150.0 * pca.components_[0] prev_pixel = np.array([y_c + top, x_c + left]) - 150.0 * pca.components_[0] angle = np.rad2deg(np.arccos(np.dot(np.array([1.0, 0.0]), pca.components_[0]))) print(f'the angle with the y-axis is {angle} deg') rotated = skimage.transform.rotate(roi, angle=angle, center=(y_c, x_c), resize=True) print(np.any(rotated)) io.imsave('C:\\Users\\radoslav\\Desktop\\rotated.png', rotated, check_contrast=False) outline = np.logical_xor(rotated, binary_erosion(rotated, footprint=np.ones((3, 3)))) io.imsave('C:\\Users\\radoslav\\Desktop\\rotated_outline.png', outline, check_contrast=False) outline_yy, outline_xx = np.nonzero(outline) xs_by_y: typing.Dict[int, List[int]] = {} for y, x in zip(outline_yy, outline_xx): xs_by_y.setdefault(y, []).append(x) y_sort_inds = np.argsort(outline_yy) col_outline = np.zeros((outline.shape[0], outline.shape[1], 3), dtype=np.uint8) for idx in y_sort_inds: y = outline_yy[idx] left = min(xs_by_y[y]) right = max(xs_by_y[y]) col_outline[y, left] = [0, 255, 0] col_outline[y, right] = [0, 0, 255] io.imsave('C:\\Users\\radoslav\\Desktop\\left_right.png', col_outline) right_outline = outline.copy() mask_out_idx = np.argwhere(outline_xx < x_c) right_outline[outline_yy[mask_out_idx], outline_xx[mask_out_idx]] = False left_outline = outline.copy() mask_out_idx = np.argwhere(outline_xx > x_c) left_outline[outline_yy[mask_out_idx], outline_xx[mask_out_idx]] = False io.imsave('C:\\Users\\radoslav\\Desktop\\left_outline.png', left_outline, check_contrast=False) io.imsave('C:\\Users\\radoslav\\Desktop\\right_outline.png', right_outline, check_contrast=False) self._viz_commands = [ line_command(QPoint(round(prev_pixel[1]), round(prev_pixel[0])), QPoint(round(next_pixel[1]), round(next_pixel[0])), pen) ] return self._viz_commands
[docs] def viz_right_release(self, pos: QPoint) -> List[PaintCommand]: self._viz_active = False return []
[docs] def viz_hover_move(self, new_pos: QPoint, old_pos: QPoint) -> List[PaintCommand]: return self._viz_commands