#!/Users/cdurkin/opt/anaconda3/bin/python3 #C:/Users/chuffard/AppData/Local/miniconda3 import numpy as np import pandas as pd import matplotlib.pyplot as plt import os , sys import cv2 import glob def create_bg_max_img(files, f,num_of_bg_imgs ): photo_max=None #Create a max pixel image of the previous 20 images #But if within the first 20 images taken, create a max pixel image of the next 20 images that were taken afterward #This means we can't start calculating data until atleast 41 images have been collected. count=num_of_bg_imgs while count>0: if f>=num_of_bg_imgs: photo=cv2.imread(files[f-count]) else: photo=cv2.imread(files[f+count]) photo_hsv=cv2.cvtColor(photo,cv2.COLOR_BGR2HSV) photo_value=photo_hsv[:,:,2] photo_value=cv2.normalize(photo_value,None,0, 255,cv2.NORM_MINMAX) if np.array(photo_max).any() == None: photo_max=photo_value.copy() else: max_values=photo_max.astype(int)-photo_value.astype(int) photo_max[max_values<0]=photo_value[max_values<0] count=count-1 return(photo_max) def subtract_bg(files,f,photo_max): photo=cv2.imread(files[f]) photo_hsv=cv2.cvtColor(photo,cv2.COLOR_BGR2HSV) photo_value=photo_hsv[:,:,2] photo_norm=cv2.normalize(photo_value,None,0,255,cv2.NORM_MINMAX) photo_denoise1=photo_norm-photo_max.astype(int) if np.min(photo_denoise1)<0: photo_denoise=photo_denoise1+abs(np.min(photo_denoise1)) else: photo_denoise=photo_denoise1.copy() photo_denoise=cv2.normalize(photo_denoise,None,0,255,cv2.NORM_MINMAX) photo_blur=cv2.medianBlur(cv2.convertScaleAbs(photo_max),251) photo_blur=abs(photo_blur.astype(int)-255) photo_nobg=photo_denoise-photo_blur if np.min(photo_nobg)<0: photo_nobg=photo_nobg+abs(np.min(photo_nobg)) photo_nobg=cv2.normalize(photo_nobg,None,0, 255,cv2.NORM_MINMAX) return(photo_nobg) def find_circle_mask(photo_max): circle_markers=cv2.Canny(cv2.convertScaleAbs(photo_max),25,25) kernel = np.ones((5, 5), np.uint8) circle_marker_dilation=cv2.dilate(circle_markers,kernel,1) contours, hierarchy = cv2.findContours(circle_marker_dilation, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_NONE) circle_markers2=np.zeros_like(circle_markers) for cnt in contours: cv2.drawContours(circle_markers2,[cnt],-1,255,-1) circle_markers2=cv2.erode(circle_markers2,kernel,1) contours,_= cv2.findContours(cv2.convertScaleAbs(circle_markers2), cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) areas = [cv2.contourArea(c) for c in contours] sorted_areas = np.sort(areas) cnt=contours[areas.index(sorted_areas[-1])] (x,y),radius = cv2.minEnclosingCircle(cnt) center = (int(x),int(y)) radius = int(radius)-50 mask=np.zeros_like(photo_max) cv2.circle(mask,center,radius,(255),-1) return(mask) def detect_marker_pixels(mask, photo_nobg): markers=cv2.adaptiveThreshold(cv2.convertScaleAbs(photo_nobg), 255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,801, 3) markers[mask==0]=0 kernel = np.ones((5, 5), np.uint8) marker_erosion=cv2.erode(markers,kernel,1) marker_dilation=cv2.dilate(marker_erosion,kernel,1) contours, hierarchy = cv2.findContours(marker_dilation, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_NONE) markers2=np.zeros_like(markers) for cnt in contours: cv2.drawContours(markers2,[cnt],-1,255,-1) detected_img=markers2.astype('ubyte') return(detected_img) # def measure_particle_props(detected_img,files,f): # particle_mask=detected_img.copy() # contours, hierarchy = cv2.findContours(particle_mask, cv2.RETR_EXTERNAL , cv2.CHAIN_APPROX_NONE) # count=0 # particle_area = [] # particle_ESD = [] # particle_perimeter = [] # file_name = [] # topleft_x = [] # topleft_y = [] # width=[] # height=[] # particle_numberID=[] # scale= 0.07194 # scale_area = scale**2 # for cnt in contours: # count=count+1 # px_area=cv2.contourArea(cnt) # um_area = px_area / scale_area # perimeter=cv2.arcLength(cnt, True)/scale # ESD=2*(np.sqrt(um_area/np.pi)) # x,y,w,h=cv2.boundingRect(cnt) # particle_area.append(um_area) # particle_ESD.append(ESD) # particle_perimeter.append(perimeter) # file_name.append(os.path.basename(files[f])) # topleft_x.append(x) # topleft_y.append(y) # width.append(w) # height.append(h) # particle_numberID.append(count) # data = pd.DataFrame(np.stack((particle_numberID, particle_area, particle_ESD, particle_perimeter, file_name, topleft_x,topleft_y,width,height),-1),columns=['Number','Area','ESD','perimeter','file_name', 'topleft_x','topleft_y','width','height']) # return(data) # def outline_detected(detected_img,files,f): # particle_edges=cv2.Canny(detected_img,100,200,5) # kernel = np.ones((5, 5), np.uint8) # edge_dilation=cv2.dilate(particle_edges,kernel,1) # example_img=cv2.imread(files[f]) # example_img[edge_dilation==255]=[127,0,255] # return(example_img) def measure_atn(mask, photo_max,files, f): photo=cv2.imread(files[f]) photo_red=photo[:,:,2] ##cv2 reads images as BGR, so red is the third channel attenuation=np.mean(-np.log(photo_red[mask==255]/photo_max[mask==255])) file_name=os.path.basename(files[f]) data=pd.DataFrame([[file_name,attenuation]],columns=['file_name','atn']) return(data) #im_path=sys.argv[1] out_path='C:/SES_out' #import the files names im_path='C:/SES_in' #files= glob.glob(os.path.join(im_path,'*.jpg')) fileslist = glob.glob("C:/SES_in/*.jpg") #for some reason it's making the second slash a backslash instead of forward. Replace it fileslist = [path.replace('\\', '/') for path in fileslist] filesdf = pd.DataFrame(fileslist, columns=['filenames']) if os.path.isdir(out_path)==False: os.mkdir(out_path) files = filesdf[filesdf['filenames'].str.contains('Ext')] files['date'] = files['filenames'].str.split('_').str[-1] files['collect_time'] = files['filenames'].str.split('_').str[-3] files=files.sort_values(by=['date']) sorted_filelist = files['filenames'].tolist() #Identify the files that needs to be processed #Open existing data file and find the name of the last image file that was analyzed and analyze every image after that one if os.path.isfile(os.path.join(out_path,os.path.basename(out_path)+'_atn.csv')): data_link=open(os.path.join(out_path,os.path.basename(out_path)+'_atn.csv'),'r') last_line=data_link.readlines()[-1] data_link.close() for x in np.flip(np.arange(0,len(sorted_filelist))): if sorted_filelist[x].split('/')[-1] in last_line: files_to_be_analyzed=np.arange(x+1,len(sorted_filelist)) break #If no data file exists, then just start with the first image else: files_to_be_analyzed=np.arange(0,len(sorted_filelist)) #Create an empty dataframe for new data to be recorded num_of_bg_imgs=20 if len(sorted_filelist)>(num_of_bg_imgs*2): for f in files_to_be_analyzed: #all_data = pd.DataFrame(columns=['Number','Area','ESD','perimeter','file_name', 'topleft_x','topleft_y','width','height']) all_atn_data=pd.DataFrame(columns=['file_name','atn']) photo_max=create_bg_max_img(sorted_filelist,f,num_of_bg_imgs) mask=find_circle_mask(photo_max) atn_data=measure_atn(mask,photo_max,sorted_filelist,f) photo_nobg=subtract_bg(sorted_filelist,f,photo_max) detected_img = detect_marker_pixels(mask,photo_nobg) # example_img=outline_detected(detected_img,sorted_filelist,f) # data=measure_particle_props(detected_img,sorted_filelist,f) # all_data=pd.concat([all_data,data]) all_atn_data=pd.concat([all_atn_data,atn_data]) #Save the data to the existing file, or create a new file # if os.path.isfile(os.path.join(out_path,os.path.basename(out_path)+'_All_particle_measurements.csv')): # all_data.to_csv(os.path.join(out_path,os.path.basename(out_path)+'_All_particle_measurements.csv'), mode='a', header=False) # else: # all_data.to_csv(os.path.join(out_path,os.path.basename(out_path)+'_All_particle_measurements.csv')) if os.path.isfile(os.path.join(out_path,os.path.basename(out_path)+'_atn.csv')): all_atn_data.to_csv(os.path.join(out_path,os.path.basename(out_path)+'_atn.csv'), mode='a', header=False) else: all_atn_data.to_csv(os.path.join(out_path,os.path.basename(out_path)+'_atn.csv')) # cv2.imwrite(os.path.join(out_path,'Outline_'+str(os.path.basename(sorted_filelist[f]))),example_img)