Commit cc69b595 authored by Josef Brandt's avatar Josef Brandt

First steps to KennardStone Implementation and Hu Moments

parent 18a37237
import numpy as np
import cv2
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from scipy import spatial
from itertools import combinations
import sys
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard.analysis.particleContainer import ParticleContainer
from gepard.analysis import particleAndMeasurement as pm
from methods import SubsamplingMethod
def get_pca(data: np.ndarray, numComp: int = 2) -> np.ndarray:
standardizedData = StandardScaler().fit_transform(data)
pca = PCA(n_components=numComp)
princComp: np.ndarray = pca.fit_transform(np.transpose(standardizedData))
return princComp
class ChemometricSubsampling(SubsamplingMethod):
def __init__(self, particleContainer: ParticleContainer, desiredFraction: float):
super(ChemometricSubsampling, self).__init__(particleContainer, desiredFraction)
def label(self) -> str:
return 'Chemometric Selection'
def apply_subsampling_method(self) -> list:
return []
def _get_particle_featurematrix(self) -> np.ndarray:
vectors: list = []
for particle in self.particleContainer.particles:
extractor: FeatureExtractor = FeatureExtractor(particle)
vectors.append(extractor.get_characteristic_vector())
vectors: np.ndarray = np.transpose(np.array(vectors))
return vectors
class FeatureExtractor(object):
def __init__(self, particle: pm.Particle):
super(FeatureExtractor, self).__init__()
self.particle: pm.Particle = particle
def get_characteristic_vector(self) -> np.ndarray:
return self._get_log_hu_moments()
def _get_log_hu_moments(self) -> np.ndarray:
moments: dict = cv2.moments(self.particle.contour)
resultMoments: np.ndarray = np.zeros((7, 1))
for index, mom in enumerate(cv2.HuMoments(moments)):
if mom != 0:
resultMoments[index] = -1 * np.copysign(1.0, mom) * np.log10(abs(mom))
else:
resultMoments[index] = 0
return resultMoments[:, 0]
class KennardStone(object):
def __init__(self, data: np.ndarray, desiredFraction: float):
super(KennardStone, self).__init__()
self.data: np.ndarray = data
self.fraction: float = desiredFraction
def get_sampled_indices(self) -> list:
pass
def _get_start_indices(self) -> list:
"""
Finds the indices of the points that are furthest apart.
Adapted from https://stackoverflow.com/questions/50468643/finding-two-most-far-away-points-in-plot-with-many-points-in-python/50469147
:return:
"""
candidates = self.data[spatial.ConvexHull(self.data).vertices]
import matplotlib.pyplot as plt
# plt.scatter(self.data[:, 0], self.data[:, 1])
# plt.plot(candidates[:, 0], candidates[:, 1])
# plt.show()
dist_mat = spatial.distance_matrix(candidates, candidates)
i, j = np.unravel_index(dist_mat.argmax(), dist_mat.shape)
index1 = np.where(self.data == candidates[i])[0][0]
index2 = np.where(self.data == candidates[j])[0][0]
return sorted([index1, index2])
def _get_point_furthest_from_other_points(self, refPoints: np.ndarray, otherPoints: np.ndarray) -> int:
index: int = -1
maxDist: float = 0.0
for i in range(otherPoints.shape[0]):
point = otherPoints[i, :]
dist = 0
for j in range(refPoints.shape[0]):
point2 = refPoints[j]
dist += (point[0]-point2[0])**2 + (point[1]-point2[1])**2
if dist > maxDist:
maxDist = dist
index = i
return index
import unittest
import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt
sys.path.append("C://Users//xbrjos//Desktop//Python")
from gepard.analysis import particleAndMeasurement as pm
from gepard.analysis.particleContainer import ParticleContainer
from gepard import dataset
import chemometricMethods as cmeth
class TestFeatureExtractor(unittest.TestCase):
def setUp(self) -> None:
self.extractor: cmeth.FeatureExtractor = cmeth.FeatureExtractor(None)
def test_get_contour_moments(self):
imgs = []
imgA: np.ndarray = np.zeros((200, 200), dtype=np.uint8)
cv2.putText(imgA, 'A', (25, 175), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=7, color=1, thickness=5)
imgs.append(imgA.copy())
imgA_translated: np.ndarray = np.zeros((200, 200), dtype=np.uint8)
cv2.putText(imgA_translated, 'A', (10, 180), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=7, color=1, thickness=5)
imgs.append(imgA_translated)
imgs.append(cv2.rotate(imgA, cv2.ROTATE_90_CLOCKWISE))
imgs.append(cv2.rotate(imgA, cv2.ROTATE_180))
imgs.append(cv2.resize(imgA, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR))
imgs.append(cv2.resize(imgA, None, fx=1.5, fy=1.5, interpolation=cv2.INTER_LINEAR))
moments: np.ndarray = np.zeros((7, len(imgs))) # we prepare an empty array for 7 hu moments per image
for i, img in enumerate(imgs):
contours, hierarchy = cv2.findContours(img, 1, 2)
particle: pm.Particle = pm.Particle()
particle.contour = contours[0]
self.extractor.particle = particle
hu: np.ndarray = self.extractor._get_log_hu_moments()
moments[:, i] = hu
# The first six hu moments are supposed to be invariant to scale, rotation and translation
# Small errors can occur, as the test image is of low resolution...
for i in range(6):
diff: np.ndarray = moments[i, :] - np.mean(moments[i, :])
self.assertFalse(np.any(diff > 0.1))
class TestKennardStone(unittest.TestCase):
def setUp(self) -> None:
self.kennardStone: cmeth.KennardStone = cmeth.KennardStone(np.array([]), 0.1)
def test_get_sampled_indices(self):
pass
def test_get_start_indices(self):
points: list = [[0, 0], [10, 10]]
for _ in range(10):
points.append([np.random.rand()*5 + 2.5, np.random.rand()*5 + 2.5])
self.kennardStone.data = np.array(points)
startIndices: list = self.kennardStone._get_start_indices()
self.assertEqual(startIndices, [0, 1])
points.append([20, 20])
self.kennardStone.data = np.array(points)
startIndices = self.kennardStone._get_start_indices()
self.assertEqual(startIndices, [0, len(points)-1])
points.insert(4, [-10, -10])
self.kennardStone.data = np.array(points)
startIndices = self.kennardStone._get_start_indices()
self.assertEqual(startIndices, [4, len(points) - 1])
def test_get_point_furthest_from_other_points(self):
otherPoints: list = [[0, 0], [10, 0], [0, 10], [10, 10]]
refPoints: list = [[2, 2]]
indexOfFurthestPoint = self.kennardStone._get_point_furthest_from_other_points(np.array(refPoints),
np.array(otherPoints))
self.assertEqual(indexOfFurthestPoint, 3)
refPoints: list = [[9, 9]]
indexOfFurthestPoint = self.kennardStone._get_point_furthest_from_other_points(np.array(refPoints),
np.array(otherPoints))
self.assertEqual(indexOfFurthestPoint, 0)
refPoints: list = [[2, 2], [3, 3], [-1, -5]]
indexOfFurthestPoint = self.kennardStone._get_point_furthest_from_other_points(np.array(refPoints),
np.array(otherPoints))
self.assertEqual(indexOfFurthestPoint, 3)
class TestChemometricSubsampling(unittest.TestCase):
def setUp(self) -> None:
particleContainer: ParticleContainer = ParticleContainer(None)
numParticles: int = 5
particleContainer.initializeParticles(numParticles)
img: np.ndarray = np.zeros((20, 20), dtype=np.uint8)
cv2.putText(img, 'A', (2, 2), fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=1, color=1, thickness=2)
contours, hierarchy = cv2.findContours(img, 1, 2)
particleContainer.setParticleContours([contours[0] for i in range(numParticles)])
self.chemSubs: cmeth.ChemometricSubsampling = cmeth.ChemometricSubsampling(particleContainer, desiredFraction=0.1)
def test_get_particle_featurematrix(self):
features: np.ndarray = self.chemSubs._get_particle_featurematrix()
self.assertEqual(features.shape, (7, 5))
for i in range(6):
diff: np.ndarray = features[i, :] - np.mean(features[i, :])
self.assertFalse(np.any(diff > 0.1))
# def test_pca(self):
# fname = r'C:\Users\xbrjos\Desktop\temp MP\190326_MCII_WWTP_SB_50_1\190326_MCII_WWTP_SB_50_1.pkl'
# fname = r'C:\Users\xbrjos\Desktop\temp MP\190313_Soil_5_A_50_5_1_50_1\190313_Soil_5_A_50_5_1_50_1.pkl'
# fname = r'C:\Users\xbrjos\Desktop\temp MP\190201_BSB_Stroomi_ds2_R1_R2_50\190201_BSB_Stroomi_ds2_R1_R2_50.pkl'
# dset: dataset.Dataset = dataset.loadData(fname)
# self.chemSubs.particleContainer = dset.particleContainer
# princComp: np.ndarray = cmeth.get_pca(self.chemSubs._get_particle_featurematrix())
# plt.scatter(princComp[:, 0], princComp[:, 1])
# plt.title(dset.name)
# plt.show()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment