Skip to content

Commit

Permalink
Merge pull request #1 from brandon-hastings/structure-overhaul-wip-BH
Browse files Browse the repository at this point in the history
Structure overhaul wip bh
  • Loading branch information
brandon-hastings authored Jun 27, 2023
2 parents a704b34 + cb071f0 commit 7336fba
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 234 deletions.
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: PatternAnalysis
name: Lumeleon
channels:
- conda-forge
- defaults
Expand Down
22 changes: 9 additions & 13 deletions extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,22 @@ def extract(mask, raw):
masked_mask = np.array(masked[:, :, 0], copy=True, dtype=bool).astype(float)
masked_mask[original_mask == 0] = np.nan

def lum_convert(arr):
red = 0.2126
green = 0.7152
blue = 0.0722
red_ch = np.multiply(arr[:, :, 0], red)
green_ch = np.multiply(arr[:, :, 1], green)
blue_ch = np.multiply(arr[:, :, 2], blue)
lum_arr = np.add(red_ch, green_ch, blue_ch)
return lum_arr
# def lum_convert(arr):
# red = 0.2126
# green = 0.7152
# blue = 0.0722
# red_ch = np.multiply(arr[:, :, 0], red)
# green_ch = np.multiply(arr[:, :, 1], green)
# blue_ch = np.multiply(arr[:, :, 2], blue)
# lum_arr = np.add(red_ch, green_ch, blue_ch)
# return lum_arr


img_yuv = cv2.cvtColor(original[:,:,[2,1,0]], cv2.COLOR_BGR2YUV)
luma, u, v = cv2.split(img_yuv)
# calc_luma = lum_convert(original)
light = luma[np.where(masked_mask == 1)]
dark = luma[np.where(masked_mask == 0)]
# print(light)
# print(luma[masked_mask == 1])
# print(dark)
# print(luma[masked_mask == 0])

light_luma = np.mean(light) / np.max(luma)
dark_luma = np.mean(dark) / np.max(luma)
Expand Down
16 changes: 12 additions & 4 deletions patternAnalysis.py → lumeleon_gui.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import tkinter as tk
import match_gui as match
import segment_gui
import match
import segment
import uv_extract
import extract
from tkinter import filedialog
from tkinter import simpledialog
window = tk.Tk()
window.title("Lumeleon")
print(type(window))


standardframe = tk.Frame(window)
Expand Down Expand Up @@ -60,9 +61,9 @@ def clusters_dialog(self):
parent=window,
minvalue=0, maxvalue=10)
if self.uv_value.get() == 1:
segment_gui.main(folder=folder_path, N_cluster=N_cluster, uv=True, toplevel=window)
segment.segment_gui(folder=folder_path, N_cluster=N_cluster, uv=True, toplevel=window)
else:
segment_gui.main(folder=folder_path, N_cluster=N_cluster, uv=False, toplevel=window)
segment.segment_gui(folder=folder_path, N_cluster=N_cluster, uv=False, toplevel=window)
self.entry.delete(0, tk.END)

def extract_values(self):
Expand Down Expand Up @@ -93,4 +94,11 @@ def action_button_conditions(self):
FileBrowseAction(master=maskframe, step_num=2, step_name="Mask images")
FileBrowseAction(master=extractframe, step_num=3, step_name="Extract luminance")


def on_closing():
window.destroy()


window.protocol("WM_DELETE_WINDOW", on_closing)

window.mainloop()
118 changes: 63 additions & 55 deletions match_gui.py → match.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
import cv2
import rawpy
import os
import shutil
import sys

import utils


def main(folder):
folder = utils.correctPath(folder)

os.chdir(folder)
if 'modified' in os.listdir():
shutil.rmtree('modified')
os.makedirs('modified')

points = []
L=[]
for file in os.listdir():
if file.endswith('.CR2'):
raw = rawpy.imread(file)
img = raw.postprocess()
clone = img.copy()
WinCoords = utils.SavePoints(img)
points.append(WinCoords)
Y = [points[-1][0][1], points[-1][1][1]]
X = [points[-1][0][0], points[-1][1][0]]
# convert to HLS color channel
clone = cv2.cvtColor(clone, cv2.COLOR_BGR2HLS)
# max amount of pixels in luminance channel of cropped section (standard)
crop = clone[min(Y):max(Y), min(X):max(X), 1]
# take mean of standard and append to list L
L.append(crop.mean())
if len(L)>1:
# difference between luminance of first (ref image) and last image in L
delta = L[-1] - L[0]
# adjust pixels in images based on delta value
clone[:, :, 1] = clone[:, :, 1] - delta
# scale "overwhite" pixels (>255) back to white
clone[:, :, 1][clone[:, :, 1]>255] = 255
# convert image back to BGR channel
img = cv2.cvtColor(clone, cv2.COLOR_HLS2BGR)
# save image in RGB not BGR
cv2.imwrite('modified/' + file[:-4] + 'modified.png', img[:, :, [2, 1, 0]])

if len(L)==1:
img = cv2.cvtColor(clone, cv2.COLOR_HLS2BGR)
cv2.imwrite('modified/' + file[:-4] + 'ref.png', img[:, :, [2, 1, 0]])

os.chdir("../")


if __name__ == '__main__':
main()
import cv2
import rawpy
import os
import shutil
import sys
# import custom utils file
import utils


def main(folder=None):
# check if argument is called from gui
if folder is not None:
argument = utils.correctPath(folder)
# if not, get command line argument as folder path
else:
argument = sys.argv[1]
if len(argument) != 2:
print("usage:python match.py ImageFolder")
return

os.chdir(argument)
if 'modified' in os.listdir():
shutil.rmtree('modified')
os.makedirs('modified')

points = []
L=[]
for file in os.listdir():
if file.endswith('.CR2'):
raw = rawpy.imread(file)
img = raw.postprocess()
clone = img.copy()
WinCoords = utils.SavePoints(img)
points.append(WinCoords)
Y = [points[-1][0][1], points[-1][1][1]]
X = [points[-1][0][0], points[-1][1][0]]
# convert to HLS color channel
clone = cv2.cvtColor(clone, cv2.COLOR_BGR2HLS)
# max amount of pixels in luminance channel of cropped section (standard)
crop = clone[min(Y):max(Y), min(X):max(X), 1]
# take mean of standard and append to list L
L.append(crop.mean())
if len(L)>1:
# difference between luminance of first (ref image) and last image in L
delta = L[-1] - L[0]
# adjust pixels in images based on delta value
clone[:, :, 1] = clone[:, :, 1] - delta
# scale "overwhite" pixels (>255) back to white
clone[:, :, 1][clone[:, :, 1]>255] = 255
# convert image back to BGR channel
img = cv2.cvtColor(clone, cv2.COLOR_HLS2BGR)
# save image in RGB not BGR
cv2.imwrite('modified/' + file[:-4] + 'modified.png', img[:, :, [2, 1, 0]])

if len(L)==1:
img = cv2.cvtColor(clone, cv2.COLOR_HLS2BGR)
cv2.imwrite('modified/' + file[:-4] + 'ref.png', img[:, :, [2, 1, 0]])

os.chdir("../")


if __name__ == '__main__':
main()
175 changes: 175 additions & 0 deletions segment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import os
from skimage import io
from sklearn.cluster import MiniBatchKMeans
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from pathlib import Path
import numpy as np
import fnmatch
import sys
import cv2
import utils
import tkinter as tk


'''MAIN SEGMENTATION METHOD VIA KMEANS SKIMAGE, CALLABLE FROM COMMAND LINE OR GUI'''


def sk_segment(file=None, N_cluster=None):
trigger = False
if None not in (file, N_cluster):
file = file
N_cluster = N_cluster
trigger = True
else:
if len(sys.argv) != 3:
print("usage:python match.py image N_clusters")
return

file = sys.argv[1]
N_cluster = int(sys.argv[2])

I = io.imread(file).astype(np.uint8)

I = I[:,:,:3]

# I = I - np.min(I)
# I = I / np.max(I)

m = I.shape[0]
n = I.shape[1]


x = np.reshape(I, (m*n, 3))
model = MiniBatchKMeans(n_clusters= N_cluster, init='k-means++', max_iter=100, batch_size=2048, verbose=0, compute_labels=True, random_state=None, tol=0.0, max_no_improvement=10, init_size=None, n_init=5, reassignment_ratio=0.01).fit(x)

p = model.predict(x)

levels = np.unique(p)
fig = plt.figure(figsize=(8,8), dpi=100)
axs = fig.subplots(len(levels),2)
for i in levels:
b = np.reshape((p==i)*1,(m,n))

axs[i,0].imshow(b)
axs[i,0].axis('off')

axs[i,1].imshow(I * np.repeat(b[:, :, np.newaxis],3,axis=2))
axs[i,1].axis('off')
axs[i,1].text(50, 200, str(i), c='r', fontsize=10)

if trigger is False:
fig.show()

key = ' '
keys = [str(i) for i in range(N_cluster)] + ['q']
while key not in keys:
key = input('Which mask to save? or [q] to quit. ')

if key == 'q':
return
i = int(key)
b = np.reshape((p==i)*1,(m,n))
io.imsave(file[:-4]+'_'+str(N_cluster)+'.png', (I * np.repeat(b[:, :, np.newaxis],3,axis=2)).astype(np.uint8))
# io.imshow(file[:-4]+'_'+str(N_cluster)+'.png')

elif trigger is True:
return [fig, p, m, n]


'''FUNCTIONS BELOW ARE FOR GUI FUNCTIONALITY'''


def cv_segment(image, N_cluster):

# image = image[:, :, :3]
pixel_vals = image.reshape((-1, 3))

fig = Figure(figsize=(8, 8), dpi=100)
axs = fig.subplots(N_cluster - 1, 2)
# list for use in elbow graph
# wcss = []
for i in range(2, N_cluster+1):
pixel_vals = np.float32(pixel_vals)

'''using cv2 kmeans clustering here as it gives better visual representation of
image clustering to user than sklearn'''
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
compactness, labels, centers = cv2.kmeans(pixel_vals, i, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# wcss.append(compactness)
# convert data into 8-bit values
centers = np.uint8(centers)
segmented_data = centers[labels.flatten()]
# reshape data into the original image dimensions
segmented_image = segmented_data.reshape(image.shape)
i = i - 2
axs[i, 0].imshow(image)
axs[i, 0].axis('off')

axs[i, 1].imshow(segmented_image)
axs[i, 1].axis('off')
axs[i, 1].text(50, 200, str(i+2), c='r', fontsize=10)
return fig


def segment_gui(folder, N_cluster, toplevel, uv=False):
folder = utils.correctPath(folder)
if os.path.exists(Path(folder) / ".DS_Store"):
os.remove(Path(folder) / ".DS_Store")

# for every file in folder run a function that returns the modified image after input to a different function to
# save
def choose_clusters(file_path):
subroot = tk.Toplevel(toplevel)
subroot.title(str(file)+" ORIGINAL")

image = io.imread(file_path).astype(np.uint32)
if uv:
image[image == np.nan] = 0

image = image[:, :, :3]

def choose_segments(n_cluster):
seg_root = tk.Toplevel(subroot)
seg_root.title(str(file)+" CLUSTERED")
# image = io.imread(Path(folder) / file).astype(np.uint32)
# n_cluster = int(n_cluster) + 2
n_cluster = int(n_cluster)
fig, p, m, n = sk_segment(file_path, n_cluster)

def save_mask(selection):
i = int(selection)
b = np.reshape((p == i) * 1, (m, n))
savefile = file[:-4] + '_' + str(n_cluster) + '_' + str(selection) + '.png'
io.imsave(Path(folder) / savefile, (image * np.repeat(b[:, :, np.newaxis], 3, axis=2)).astype(np.uint8))
seg_root.quit()

utils.image_selection(seg_root, n_cluster, save_mask, utils.pop_up(fig, seg_root), end=0)

def seg_closing():
seg_root.destroy()

seg_root.protocol("WM_WINDOW_DELETE", seg_closing)
tk.mainloop()
seg_root.destroy()
subroot.quit()

utils.image_selection(subroot, N_cluster, choose_segments, utils.pop_up(cv_segment(image=image[:, :, :3],
N_cluster=N_cluster),
subroot), start=2, end=1)

def sub_closing():
subroot.destroy()
sys.exit()

subroot.protocol("WM_WINDOW_DELETE", sub_closing)
tk.mainloop()
subroot.destroy()

for file in fnmatch.filter(sorted(os.listdir(folder)), '*e?.png'):
file_path = Path(folder) / file
choose_clusters(file_path)


if __name__ == '__main__':
sk_segment()
Loading

0 comments on commit 7336fba

Please sign in to comment.