Скачиваний:
0
Добавлен:
13.05.2026
Размер:
6.53 Кб
Скачать
import os
import time
import typing as typ
import numpy as np
import numpy.typing as npt
import matplotlib.pyplot as plt #type: ignore
from skimage import io #type: ignore
from threading import Thread

#Создание класса-наследника класса Thread с возвращением элементов
class ThreadRV(Thread):

    def __init__(self,group=None,target=None,name=None,\
        args=(),kwargs={},Verbose=None):
        Thread.__init__(self,group,target,name,args,kwargs)
        self._return = None

    def run(self):
        if self._target is not None:
            self._return = self._target(*self._args,**self._kwargs)

    def result(self):
        return self._return

#Функция вызова потоков
def thrd_call(trg: typ.Callable[...,typ.Any],\
    argnt1: tuple,argnt2: tuple,a: bool) -> typ.Any:
    thread1 = ThreadRV(target=trg,args =argnt1)
    thread2 = ThreadRV(target=trg,args =argnt2)
    thread1.start()
    thread2.start()
    if a == False:
        thread2.join()
        thread1.join()
    elif a == True:
        thread1.join()
        thread2.join()
        return (thread1.result(),thread2.result())

#Функция считывания названий файлов
def f_name(s: str) -> typ.List[str]:
    lt = os.listdir(s)
    return lt

#Функция создания списков изображений
def img_read(ls: typ.List[str],path: str)\
 -> typ.List[npt.NDArray[np.float32]]:
    array: typ.List[npt.NDArray[np.float32]] = []
    for i in ls:
        array.append(\
            np.array(io.imread(f'{path}/{i}'),dtype=np.float32))
    return array

#Функция «спрямления» изображений
def img_flatten(ls:typ.List[npt.NDArray[np.float32]]) -> None:
	for i in ls:
		i.shape = (len(i)*len(i[0])*3) #type: ignore
		i = i.T

#Функция нормирования параметров
def norm(arr: npt.NDArray[np.float32],\
    mn: npt.NDArray[np.float32],\
    st: npt.NDArray[np.float32]) -> None:
    for i in range(len(arr)):
        arr[i] = (arr[i] - mn[i])/st[i]

#Очистка окна консоли
os.system('cls')

#Запуск таймера
t1: float = time.perf_counter_ns()

#Создание списков названий файлов в папках
trees_list: typ.List[str]; no_trees_list: typ.List[str]
trees_list, no_trees_list = thrd_call(f_name,\
    ("Trees",),("NoTrees",),True)

#Создание списков изображений в папке
trees_img_list: typ.List[npt.NDArray[np.float32]]
no_trees_img_list: typ.List[npt.NDArray[np.float32]]
trees_img_list, no_trees_img_list = thrd_call(img_read,\
    (trees_list,"Trees"),(no_trees_list,"NoTrees"),True)
del trees_list, no_trees_list

#Создание массива изображений
##«Спрямление» массивов изображений
thrd_call(img_flatten,(trees_img_list,),(no_trees_img_list,),False)
##Объединение массивов в один
X: npt.NDArray[np.float32] =\
    np.vstack((np.array(trees_img_list[0:len(trees_img_list)+1]),
    np.array(no_trees_img_list[0:len(no_trees_img_list)+1]))).astype('float64')
del trees_img_list, no_trees_img_list

#Метод главных кординат
##Максимальное количество параметров
max_par: int = 2
##Среднее нормирование
mean: npt.NDArray[np.float32] = np.mean(X.T, axis=1, dtype=np.float32)
std: npt.NDArray[np.float32] = np.std(X.T, axis=1, dtype=np.float32)
norm(X.T,mean,std)
##Создание матрицы собственных векторов для ковариационной матрицы
U: npt.NDArray[np.float32]
p: bool = os.path.isfile('U_matrix.npy')
if p == True:
    ##Создание матрицы преобразований
    U = np.load('U_matrix.npy')
elif p == False:
    ##Создание ковариционной матрицы
    sigma: npt.NDArray[np.float32] = np.cov(X.T,bias=True)
    ##Создание матрицы преобразований
    U, S, Vh = np.linalg.svd(sigma)
    np.save('U_matrix.npy', U[::, :max_par:])
    del sigma, S, Vh
X_cmprs: npt.NDArray[np.float32] = X@U #Компрессия изображений
del U, p

#Построение изображений в двух главных координатах
plt.figure(1)
plt.scatter(X_cmprs.T[0],X_cmprs.T[1],alpha=0.3)
plt.title("Изображения в двух главных координатах")

#Метод K-means
k: int = 3 #количество кластеров
CK: npt.NDArray[np.float32] = \
    np.array(np.copy([X_cmprs[0],X_cmprs[1],X_cmprs[2]])) # массив центроидов
dist: npt.NDArray[np.float32] =\
    np.empty((len(X_cmprs),k),dtype=np.float32) # массив расстояний
K_number: npt.NDArray[np.int16] =\
    np.empty(len(X_cmprs),dtype=np.float32) # массив номеров кластера для каждого изображения
##Кластеризаця
tmp: npt.NDArray[np.float32] =\
    np.zeros((k,max_par),dtype=np.float32) # массив центроидов для сравнений
ClustNum: npt.NDArray[np.int16] =\
    np.empty(len(X_cmprs),dtype=np.float32) # массив номеров кластера для каждого изображения
while np.all(tmp == CK) == False:
    tmp = np.copy(CK)
    ##Вычисление расстояний до изображений
    for i in range(0,k):
        dist.T[i] = (X_cmprs.T[0]-CK[i][0])**2 + (X_cmprs.T[1]-CK[i][1])**2
    ClustNum = np.copy(np.argmin(dist,axis=1)) #определение номера кластера
    ##Обновление центров кластеров
    for i in range(0,k):
        CK[i] = np.mean(X_cmprs[ClustNum==i,:],axis=0,dtype=np.float32)
    K_number = np.copy(ClustNum)
del CK, dist, tmp, ClustNum

#Вывод графиков на экран
plt.figure(2)
for i in range(k):
    plt.scatter(X_cmprs[K_number==i,0], X_cmprs[K_number==i,1], alpha=0.4, label=f'{i+1} кластер')
plt.title('Кластеризованные Изображения в двух координатах')
plt.legend()
del k, X_cmprs, K_number

#Вывод времени выполнения программы
print(f'\nTotal program execution time: \
{(time.perf_counter_ns()-t1)/10**9:.5f} seconds.')
del t1

plt.show()
Соседние файлы в папке лабы