From 9da228ba8a13a76627592bfea946336d415b0626 Mon Sep 17 00:00:00 2001 From: Bing Zhang Date: Thu, 13 Feb 2025 09:50:56 -0600 Subject: [PATCH 1/8] add ML --- Jim_ColorHistogram_ColorScatterPlot.py | 327 +++++++++++++------------ 1 file changed, 166 insertions(+), 161 deletions(-) diff --git a/Jim_ColorHistogram_ColorScatterPlot.py b/Jim_ColorHistogram_ColorScatterPlot.py index 50e82ab..5999ab9 100644 --- a/Jim_ColorHistogram_ColorScatterPlot.py +++ b/Jim_ColorHistogram_ColorScatterPlot.py @@ -66,207 +66,212 @@ def getBiggestContour(contours, num_contours=1): except: print(traceback.format_exc()) +def image_analysis(filename): + #--------------------------------------------------imageFile is some RGB image + #'Green_Sanghyun.jpg' + imageFile = os.path.join(filename) -#--------------------------------------------------imageFile is some RGB image - -imageFile = os.path.join('Xiao_1um.png') - -pix2 = cv.imread(imageFile) - -#-------------------------------------------------Convert the BRG image to RGB -img = cv.cvtColor(pix2, cv.COLOR_BGR2RGB) - -try: - # convert to grayscale before thresholding - #(we *could* do color thresholding as well if necessary) - - grayscale_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY) - - # threshold *inverted* image (first number is cutoff value, - # second number assigned to all pixels exceeding cutoff) - - bin_img = cv.threshold(grayscale_img, - 25, - 255, - cv.THRESH_BINARY_INV)[1] - - # get list of contours: - cntrs = getContours(cv.bitwise_not(bin_img)) - - # keep biggest contour only: - cntr = getBiggestContour(cntrs) - - # show contour: - img_cntr = img.copy() - cv.drawContours(img_cntr, cntr, -1, color=(255, 0, 0), thickness=3) - fig0 = plt.imshow(img_cntr) - - # create blank mask: - mask = np.full(bin_img.shape, 0, dtype=np.uint8) - - # use biggest contour to define ROI area: - cv.drawContours(mask, cntr, -1, (255, 255, 255), cv.FILLED) - - #---------------------------------------------Convert the RGB image to HSV - pix2 = cv.cvtColor(img, cv.COLOR_RGB2HSV) - # --------------------------------------------------Splitting HSV channels - h, s, v = cv.split(pix2) - -except: - print(traceback.format_exc()) + pix2 = cv.imread(imageFile) -#--------------------------------Making some empty matrices of the same size + #-------------------------------------------------Convert the BRG image to RGB + img = cv.cvtColor(pix2, cv.COLOR_BGR2RGB) -pix_test = np.zeros((pix2.shape[0],pix2.shape[1])) -pix_mid = np.zeros((pix2.shape[0],pix2.shape[1])) + try: + # convert to grayscale before thresholding + #(we *could* do color thresholding as well if necessary) + + grayscale_img = cv.cvtColor(img, cv.COLOR_RGB2GRAY) + + # threshold *inverted* image (first number is cutoff value, + # second number assigned to all pixels exceeding cutoff) + + bin_img = cv.threshold(grayscale_img, + 25, + 255, + cv.THRESH_BINARY_INV)[1] + + # get list of contours: + cntrs = getContours(cv.bitwise_not(bin_img)) + + # keep biggest contour only: + cntr = getBiggestContour(cntrs) + + # show contour: + img_cntr = img.copy() + cv.drawContours(img_cntr, cntr, -1, color=(255, 0, 0), thickness=3) + fig0 = plt.imshow(img_cntr) + + # create blank mask: + mask = np.full(bin_img.shape, 0, dtype=np.uint8) + + # use biggest contour to define ROI area: + cv.drawContours(mask, cntr, -1, (255, 255, 255), cv.FILLED) + + #---------------------------------------------Convert the RGB image to HSV + pix2 = cv.cvtColor(img, cv.COLOR_RGB2HSV) + # --------------------------------------------------Splitting HSV channels + h, s, v = cv.split(pix2) + + except: + print(traceback.format_exc()) + + #--------------------------------Making some empty matrices of the same size + + pix_test = np.zeros((pix2.shape[0],pix2.shape[1])) + pix_mid = np.zeros((pix2.shape[0],pix2.shape[1])) + + #----------------------------------------Creating a list of all the HSV values + flat_pix2=pix2.reshape((pix2.shape[1]*pix2.shape[0],3)) + flat_mask = mask.reshape((mask.shape[1] * mask.shape[0]), 1) + + #----------------------------------------Creating a list of all the RGB values + flat_img=img.reshape((img.shape[1]*img.shape[0],3)) + + #-------------------------------------------------------------------------- + #----------------------------------------------------FILTERING------------- + #-------------------------------------------------------------------------- + dictionary_HSV = { + 'H':flat_pix2[:,0], + 'S':flat_pix2[:,1], + 'V':flat_pix2[:,2], + 'filter':flat_mask[:,0]} + + df = pd.DataFrame(dictionary_HSV) -#----------------------------------------Creating a list of all the HSV values -flat_pix2=pix2.reshape((pix2.shape[1]*pix2.shape[0],3)) -flat_mask = mask.reshape((mask.shape[1] * mask.shape[0]), 1) -#----------------------------------------Creating a list of all the RGB values -flat_img=img.reshape((img.shape[1]*img.shape[0],3)) + dictionary_RGB = { + 'R':flat_img[:,0], + 'G':flat_img[:,1], + 'B':flat_img[:,2], + 'filter':flat_mask[:,0]} -#-------------------------------------------------------------------------- -#----------------------------------------------------FILTERING------------- -#-------------------------------------------------------------------------- -dictionary_HSV = { - 'H':flat_pix2[:,0], - 'S':flat_pix2[:,1], - 'V':flat_pix2[:,2], - 'filter':flat_mask[:,0]} + dfimg = pd.DataFrame(dictionary_RGB) -df = pd.DataFrame(dictionary_HSV) + #------------------------------------Now filter just the image portion + #------------------------------------use "!=" instead of "==" to get background + df2 = df.loc[df['filter'] == 255] + df3 = dfimg.loc[dfimg['filter'] == 255] -dictionary_RGB = { - 'R':flat_img[:,0], - 'G':flat_img[:,1], - 'B':flat_img[:,2], - 'filter':flat_mask[:,0]} + #--------------------------------------------------------------------------- + #-----------------------------------------------HISTOGRAM ------------------ + #--------------------------------------------------------------------------- + from scipy.stats import circmean, circstd -dfimg = pd.DataFrame(dictionary_RGB) + #-------------------------------------------------------------------------RGB + R_DIST = df3['R'] + R_mu = np.mean(R_DIST) + R_sig = np.std(R_DIST) + G_DIST = df3['G'] + G_mu = np.mean(G_DIST) + G_sig = np.std(G_DIST) -#------------------------------------Now filter just the image portion -#------------------------------------use "!=" instead of "==" to get background -df2 = df.loc[df['filter'] == 255] -df3 = dfimg.loc[dfimg['filter'] == 255] + B_DIST = df3['B'] + B_mu = np.mean(B_DIST) + B_sig = np.std(B_DIST) -#--------------------------------------------------------------------------- -#-----------------------------------------------HISTOGRAM ------------------ -#--------------------------------------------------------------------------- -from scipy.stats import circmean, circstd + fig1, axes = plt.subplots(1, 3, sharey=False, tight_layout=True) -#-------------------------------------------------------------------------RGB -R_DIST = df3['R'] -R_mu = np.mean(R_DIST) -R_sig = np.std(R_DIST) + # We can set the number of bins with the *bins* keyword argument. + axes[0].hist(R_DIST, bins=256) + axes[0].set_title('R_dist\n' + fr'$\mu={R_mu:.0f}$, $\sigma={R_sig:.0f}$') -G_DIST = df3['G'] -G_mu = np.mean(G_DIST) -G_sig = np.std(G_DIST) + axes[1].hist(G_DIST, bins=256) + axes[1].set_title('G_dist\n' + fr'$\mu={G_mu:.0f}$, $\sigma={G_sig:.0f}$') -B_DIST = df3['B'] -B_mu = np.mean(B_DIST) -B_sig = np.std(B_DIST) - -fig1, axes = plt.subplots(1, 3, sharey=False, tight_layout=True) - -# We can set the number of bins with the *bins* keyword argument. -axes[0].hist(R_DIST, bins=256) -axes[0].set_title('R_dist\n' - fr'$\mu={R_mu:.0f}$, $\sigma={R_sig:.0f}$') - -axes[1].hist(G_DIST, bins=256) -axes[1].set_title('G_dist\n' - fr'$\mu={G_mu:.0f}$, $\sigma={G_sig:.0f}$') - -axes[2].hist(B_DIST, bins=256) -axes[2].set_title('B_dist\n' - fr'$\mu={B_mu:.0f}$, $\sigma={B_sig:.0f}$') + axes[2].hist(B_DIST, bins=256) + axes[2].set_title('B_dist\n' + fr'$\mu={B_mu:.0f}$, $\sigma={B_sig:.0f}$') -#----------------------------------------------------------------------H Data -#----------------------------------circular mean and stdev since H is a circle -H_DIST = df2['H'].round(0).astype(int) -#H_DIST = H_DIST*2 -rads = np.deg2rad(H_DIST) -circmn = circmean(rads*2) -h_mu = np.rad2deg(circmn) + #----------------------------------------------------------------------H Data + #----------------------------------circular mean and stdev since H is a circle + H_DIST = df2['H'].round(0).astype(int) + #H_DIST = H_DIST*2 + rads = np.deg2rad(H_DIST) + circmn = circmean(rads*2) + h_mu = np.rad2deg(circmn) -crcstd = circstd(rads*2) -h_sig = np.rad2deg(crcstd) + crcstd = circstd(rads*2) + h_sig = np.rad2deg(crcstd) -#-----------------------------------------------------------------------S Data -S_DIST = df2['S'] -s_mu = np.mean(S_DIST) -s_sig = np.std(S_DIST) + #-----------------------------------------------------------------------S Data + S_DIST = df2['S'] + s_mu = np.mean(S_DIST) + s_sig = np.std(S_DIST) -#-----------------------------------------------------------------------V Data -V_DIST = df2['V'] + #-----------------------------------------------------------------------V Data + V_DIST = df2['V'] -#------------For filtering just the V values from the thresholding filter -#FILTERED_V_DIST = [i for i,j in zip(V_DIST, flat_mask) if j == 255] + #------------For filtering just the V values from the thresholding filter + #FILTERED_V_DIST = [i for i,j in zip(V_DIST, flat_mask) if j == 255] -v_mu = np.mean(V_DIST) -v_sig = np.std(V_DIST) + v_mu = np.mean(V_DIST) + v_sig = np.std(V_DIST) + plt.savefig(filename+'_1.png') + fig2, axs = plt.subplots(1, 3, sharey=False, tight_layout=True) + # We can set the number of bins with the *bins* keyword argument. + axs[0].hist(H_DIST, bins=360) + axs[0].set_title('H_dist\n' + fr'$\mu={h_mu:.0f}$, $\sigma={h_sig:.0f}$') -fig2, axs = plt.subplots(1, 3, sharey=False, tight_layout=True) + axs[1].hist(S_DIST, bins=256) + axs[1].set_title('S_dist\n' + fr'$\mu={s_mu:.0f}$, $\sigma={s_sig:.0f}$') -# We can set the number of bins with the *bins* keyword argument. -axs[0].hist(H_DIST, bins=360) -axs[0].set_title('H_dist\n' - fr'$\mu={h_mu:.0f}$, $\sigma={h_sig:.0f}$') + axs[2].hist(V_DIST, bins=256) + axs[2].set_title('V_dist\n' + fr'$\mu={v_mu:.0f}$, $\sigma={v_sig:.0f}$') -axs[1].hist(S_DIST, bins=256) -axs[1].set_title('S_dist\n' - fr'$\mu={s_mu:.0f}$, $\sigma={s_sig:.0f}$') + #----------------------------------------------------------------------------- + #-----------------------------------------------SCATTER PLOT ----------------- + #----------------------------------------------------------------------------- -axs[2].hist(V_DIST, bins=256) -axs[2].set_title('V_dist\n' - fr'$\mu={v_mu:.0f}$, $\sigma={v_sig:.0f}$') -#----------------------------------------------------------------------------- -#-----------------------------------------------SCATTER PLOT ----------------- -#----------------------------------------------------------------------------- + #----------------------------------------------------------Define size of dots + area = 1.5 + #------------------------------------Making sure color values are not squished + graphbounds = pd.Series([0, pi/2, pi]) + satbounds = pd.Series([255, 255, 255]) -#----------------------------------------------------------Define size of dots -area = 1.5 + rads = pd.concat([rads, graphbounds]) + S_DIST = pd.concat([S_DIST, satbounds]) -#------------------------------------Making sure color values are not squished -graphbounds = pd.Series([0, pi/2, pi]) -satbounds = pd.Series([255, 255, 255]) + # plt.show() + plt.savefig(filename+'_2.png') + #--------------------------------------------------------------PLOTTING STARTS + fig3 = plt.figure() + axe = fig3.add_subplot(projection='polar') + axe.set_yticks([100, 200, 255]) + axe.errorbar(circmn,s_mu, + xerr= crcstd,yerr= s_sig, + capsize=7, + fmt= '^', + c='k') + c = axe.scatter(rads*2, + S_DIST, + c=rads, + s=area, + cmap='hsv', + alpha=1) -rads = pd.concat([rads, graphbounds]) -S_DIST = pd.concat([S_DIST, satbounds]) + #----------------------------------OpenCV only has H values between 0 and 180 + #ax.set_thetamin(0) + #ax.set_thetamax(180) + plt.savefig(filename+'_3.png') -#--------------------------------------------------------------PLOTTING STARTS -fig3 = plt.figure() -axe = fig3.add_subplot(projection='polar') -axe.set_yticks([100, 200, 255]) -axe.errorbar(circmn,s_mu, - xerr= crcstd,yerr= s_sig, - capsize=7, - fmt= '^', - c='k') -c = axe.scatter(rads*2, - S_DIST, - c=rads, - s=area, - cmap='hsv', - alpha=1) + return H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig -#----------------------------------OpenCV only has H values between 0 and 180 -#ax.set_thetamin(0) -#ax.set_thetamax(180) From 338bd4132a2e7457dcb0158e3f564c317c2b3bf1 Mon Sep 17 00:00:00 2001 From: Bing Zhang Date: Thu, 13 Feb 2025 09:51:04 -0600 Subject: [PATCH 2/8] add ML --- Dockerfile | 22 +++++++++ extractor_info.json | 41 +++++++++++++++++ image_analysis_extractor.py | 92 +++++++++++++++++++++++++++++++++++++ optimizer.py | 84 +++++++++++++++++++++++++++++++++ requirements.txt | 28 +++++++++++ 5 files changed, 267 insertions(+) create mode 100644 Dockerfile create mode 100644 extractor_info.json create mode 100644 image_analysis_extractor.py create mode 100644 optimizer.py create mode 100644 requirements.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..98056db --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM python:3.9 + +RUN apt-get update && apt-get install -y \ + libgl1-mesa-glx \ + libglib2.0-0 \ + libsm6 \ + libxrender-dev \ + libxext6 \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /home/clowder + +RUN python -m pip install --upgrade pip +#RUN python -m pip install pyclowder + +COPY requirements.txt ./ +#RUN pip install -r requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +COPY optimizer.py image_analysis_extractor.py Jim_ColorHistogram_ColorScatterPlot.py AnalysisToolbox_Jim.py ColorHistogram_ColorScatterPlot.py extractor_info.json ./ + +CMD python3 image_analysis_extractor.py diff --git a/extractor_info.json b/extractor_info.json new file mode 100644 index 0000000..154862c --- /dev/null +++ b/extractor_info.json @@ -0,0 +1,41 @@ +{ + "@context": "http://clowder.ncsa.illinois.edu/contexts/extractors.jsonld", + "name": "imageanalysis", + "version": "0.0.1", + "description": "image analysis extractor.", + "author": "Bing Zhang ", + "contributors": [ + "Austin Lomas " + ], + "contexts": [{ + "H_DIST": "http://clowder.ncsa.illinois.edu/metadata/warpage#H_DIST", + "h_mu": "http://clowder.ncsa.illinois.edu/metadata/warpage#h_mu", + "h_sig": "http://clowder.ncsa.illinois.edu/metadata/warpage#h_sig", + "V_DIST": "http://clowder.ncsa.illinois.edu/metadata/warpage#V_DIST", + "v_mu": "http://clowder.ncsa.illinois.edu/metadata/warpage#v_mu", + "v_sig": "http://clowder.ncsa.illinois.edu/metadata/warpage#v_sig", + "S_DIST": "http://clowder.ncsa.illinois.edu/metadata/warpage#S_DIST", + "s_mu": "http://clowder.ncsa.illinois.edu/metadata/warpage#s_mu", + "s_sig": "http://clowder.ncsa.illinois.edu/metadata/warpage#s_sig" + }], + "repository": [{ + "repType": "git", + "repUrl": "https://github.com/clowder-framework/extractors-imageanalysis" + }, + { + "repType": "docker", + "repUrl": "clowder/extractors-imageanalysis" + } + ], + "process": { + "metadata": [ + "added.file" + ] + }, + "external_services": [], + "dependencies": [], + "bibtex": [], + "labels": [ + "Type/Image" + ] +} diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py new file mode 100644 index 0000000..7a2ed4c --- /dev/null +++ b/image_analysis_extractor.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +import logging +import os +import json +import traceback +import requests +from pyclowder.extractors import Extractor +import pyclowder.files +import pyclowder.utils +from pyclowder.utils import CheckMessage +from Jim_ColorHistogram_ColorScatterPlot import image_analysis +from optimizer import optimizer_get, optimizer_tell, optimizer_init + +#TODO, Docker ENV +SCP_WEB_URL_BASE = 'http://host.docker.internal:5000/structural-color-printing/' + +class ImageAnalysisExtractor(Extractor): + def __init__(self): + Extractor.__init__(self) + # parse command line and load default logging configuration + self.setup() + # setup logging for the exctractor + logging.getLogger('pyclowder').setLevel(logging.DEBUG) + logging.getLogger('__main__').setLevel(logging.DEBUG) + self.campaign_id = None + self.opt = None + + def check_message(self, connector, host, secret_key, resource, parameters): + logger = logging.getLogger(__name__) + print(resource["type"]) + if resource["type"] == "metadata": + # check the type + if 'metadata' in resource and 'image_analysis' in resource.get('metadata'): + return CheckMessage.bypass + return CheckMessage.ignore + + def process_message(self, connector, host, secret_key, resource, parameters): + # get input file + inputfile = None + try: + file_id = resource['id'] + metadata = resource['metadata'] + campaign_id = metadata['campaign_id'] + cell_id = metadata['cell_id'] + print("campaign_id", campaign_id) + print("cell_id", cell_id) + inputfile = pyclowder.files.download(connector, host, secret_key, resource['id']) + H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig = image_analysis(inputfile) + content = { + # 'H_DIST': H_DIST.to_json(), + 'h_mu': h_mu, + 'h_sig': h_sig, + # 'V_DIST': V_DIST.to_json(), + 'v_mu': v_mu, + 'v_sig': v_sig, + # 'S_DIST': S_DIST.to_json(), + 's_mu': s_mu, + 's_sig': s_sig} + # format the conent as a metadata + # metadata = self.get_metadata(content, "file", parameters['id'], host) + + # upload metadata + # pyclowder.files.upload_metadata(connector, host, secret_key, parameters['id'], metadata) + + if self.campaign_id is None or self.campaign_id != campaign_id: + self.campaign_id = campaign_id + self.opt = optimizer_init() + + PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) + _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) + # store backt tp SCP web application + try: + url = SCP_WEB_URL_BASE + 'campaign/%s/update_cell_color' % (campaign_id) + result = requests.post(url, data=json.dumps( + {"campaign_id": campaign_id, "cell_id": cell_id, "cell_color": content, + "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight}), + headers={'Content-type': 'application/json', 'accept': 'application/json'}, + verify=False) + result.raise_for_status() + except: + traceback.print_exc() + + finally: + if inputfile: + os.remove(inputfile) + + + +if __name__ == "__main__": + extractor = ImageAnalysisExtractor() + extractor.start() \ No newline at end of file diff --git a/optimizer.py b/optimizer.py new file mode 100644 index 0000000..bd327d7 --- /dev/null +++ b/optimizer.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +""" +Created on Tue Jun 20 15:13:45 2023 + +@author: Diao Group + +Find global minima of f(x)=x**2 +""" + +import matplotlib.pyplot as plt +from skopt import Optimizer +from skopt import plots +import numpy as np +import pandas as pd +# h_mu = 70 + +# --------------------------Whatever function we want to find min +def Objective(h_mu): + result = abs(180-h_mu) + return result + + +# -----------------------What range of params can we search over +space = [(30.0, 1000.0), # -----------------------PrintSpeed range + (25.0, 45.0), # -------------------------BedTemp range + (20.0, 35.0), # -------------------------Pressure range + (0.01, 5.0) # --------------------------ZHeight range + ] + + + +# Pre-allocate a Pandas dataframe for function evaluations +ExpData = pd.DataFrame({ + 'PrintSpeed': [], + 'BedTemp': [], + 'Pressure': [], + 'ZHeight': [], + 'Error': [], + 'ExperimentNumber': [] +}) + +def optimizer_init(): + # ----------------------BO framework + opt = Optimizer(dimensions=space, + base_estimator='gp', # indirect kernel selection + n_initial_points=5, + initial_point_generator='random', + n_jobs=1, + acq_func='EI', # acquisition function + acq_optimizer='auto', + random_state=None, + model_queue_size=None, + acq_func_kwargs=None, + acq_optimizer_kwargs=None) + return opt + +def optimizer_get(opt): + # -----------------------------------------give guess of new params + PrintSpeed, BedTemp, Pressure, ZHeight = opt.ask() + return PrintSpeed, BedTemp, Pressure, ZHeight + + +def optimizer_tell(opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight): + # --------------------------------------------find value at given params + FunctionValue = Objective(h_mu) + # -------------------------------------------------put value into ans + answer = opt.tell([PrintSpeed, BedTemp, Pressure, ZHeight], FunctionValue) + + return answer + + # plots.plot_evaluations(answer, bins=20, + # dimensions=None, + # plot_dims=None) + # plt.show() + # + # plt.plot(ExpData['ExperimentNumber'], + # ExpData['Error'], + # marker='o', + # linestyle='-', + # color='k') + # plt.title('Convergence Chart') + # plt.xlabel('Experiment Number') + # plt.ylabel('Color Error') + # plt.show() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..987bdb6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,28 @@ +certifi==2024.8.30 +charset-normalizer==3.4.0 +contourpy==1.3.0 +cycler==0.12.1 +fonttools==4.54.1 +idna==3.10 +importlib_resources==6.4.5 +kiwisolver==1.4.7 +matplotlib==3.9.2 +numpy==2.0.2 +opencv-python==4.10.0.84 +packaging==24.1 +pandas==2.2.3 +pika==1.3.2 +pillow==11.0.0 +pyclowder==2.7.0 +pyparsing==3.2.0 +python-dateutil==2.9.0.post0 +pytz==2024.2 +PyYAML==6.0.2 +requests==2.32.3 +requests-toolbelt==1.0.0 +scipy==1.13.1 +six==1.16.0 +tzdata==2024.2 +urllib3==2.2.3 +zipp==3.20.2 +scikit-optimize \ No newline at end of file From b488c171245f96df41b8b14c777c60981dcf8677 Mon Sep 17 00:00:00 2001 From: Bing Zhang Date: Tue, 25 Feb 2025 23:46:10 -0600 Subject: [PATCH 3/8] send file id --- image_analysis_extractor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index 7a2ed4c..1576a56 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -73,7 +73,7 @@ def process_message(self, connector, host, secret_key, resource, parameters): try: url = SCP_WEB_URL_BASE + 'campaign/%s/update_cell_color' % (campaign_id) result = requests.post(url, data=json.dumps( - {"campaign_id": campaign_id, "cell_id": cell_id, "cell_color": content, + {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight}), headers={'Content-type': 'application/json', 'accept': 'application/json'}, verify=False) @@ -89,4 +89,4 @@ def process_message(self, connector, host, secret_key, resource, parameters): if __name__ == "__main__": extractor = ImageAnalysisExtractor() - extractor.start() \ No newline at end of file + extractor.start() From 529f6c0627ba0f16d5a451b4c97243cbeee0e8c6 Mon Sep 17 00:00:00 2001 From: bingzhang Date: Mon, 21 Apr 2025 11:33:28 -0500 Subject: [PATCH 4/8] average runs --- image_analysis_extractor.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index 1576a56..d18a04e 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -43,8 +43,14 @@ def process_message(self, connector, host, secret_key, resource, parameters): metadata = resource['metadata'] campaign_id = metadata['campaign_id'] cell_id = metadata['cell_id'] + rank_run = metadata['rank_run'] + number_prints_trigger_prediction = metadata['number_prints_trigger_prediction'] + accum_h_mu = float(metadata['accum_h_mu']) + print("campaign_id", campaign_id) print("cell_id", cell_id) + print('rank_run') + print('number_prints_trigger_prediction') inputfile = pyclowder.files.download(connector, host, secret_key, resource['id']) H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig = image_analysis(inputfile) content = { @@ -62,19 +68,31 @@ def process_message(self, connector, host, secret_key, resource, parameters): # upload metadata # pyclowder.files.upload_metadata(connector, host, secret_key, parameters['id'], metadata) - - if self.campaign_id is None or self.campaign_id != campaign_id: + data = None + if rank_run % number_prints_trigger_prediction == 0: self.campaign_id = campaign_id self.opt = optimizer_init() + if rank_run +1 == number_prints_trigger_prediction: + accum_h_mu += h_mu + h_mu = accum_h_mu/number_prints_trigger_prediction + PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) + _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, + "cell_color": content, + "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight} + else: + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, + 'rank_run': rank_run} + # if self.campaign_id is None or self.campaign_id != campaign_id: + # self.campaign_id = campaign_id + # self.opt = optimizer_init() - PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) - _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) + # PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) + # _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) # store backt tp SCP web application try: url = SCP_WEB_URL_BASE + 'campaign/%s/update_cell_color' % (campaign_id) - result = requests.post(url, data=json.dumps( - {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, - "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight}), + result = requests.post(url, data=json.dumps(data), headers={'Content-type': 'application/json', 'accept': 'application/json'}, verify=False) result.raise_for_status() From 9812ce32e33f8d4f7f86a33732142264a7fac085 Mon Sep 17 00:00:00 2001 From: bingzhang Date: Wed, 23 Apr 2025 11:25:19 -0500 Subject: [PATCH 5/8] update code --- image_analysis_extractor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index d18a04e..ec0da33 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -69,10 +69,10 @@ def process_message(self, connector, host, secret_key, resource, parameters): # upload metadata # pyclowder.files.upload_metadata(connector, host, secret_key, parameters['id'], metadata) data = None - if rank_run % number_prints_trigger_prediction == 0: + if rank_run == 0: self.campaign_id = campaign_id self.opt = optimizer_init() - if rank_run +1 == number_prints_trigger_prediction: + if (rank_run +1) % number_prints_trigger_prediction == 0: accum_h_mu += h_mu h_mu = accum_h_mu/number_prints_trigger_prediction PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) From a7a5926609aa4e98a151c21228ea59fa06cb3520 Mon Sep 17 00:00:00 2001 From: bingzhang Date: Tue, 20 May 2025 13:18:03 -0500 Subject: [PATCH 6/8] integrate printability --- Dockerfile | 2 +- image_analysis_extractor.py | 15 ++- optimizer.py | 4 +- printability.py | 191 ++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 printability.py diff --git a/Dockerfile b/Dockerfile index 98056db..64e2eb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,6 @@ COPY requirements.txt ./ #RUN pip install -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt -COPY optimizer.py image_analysis_extractor.py Jim_ColorHistogram_ColorScatterPlot.py AnalysisToolbox_Jim.py ColorHistogram_ColorScatterPlot.py extractor_info.json ./ +COPY printability.py optimizer.py image_analysis_extractor.py Jim_ColorHistogram_ColorScatterPlot.py AnalysisToolbox_Jim.py ColorHistogram_ColorScatterPlot.py extractor_info.json ./ CMD python3 image_analysis_extractor.py diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index ec0da33..386c057 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -11,6 +11,7 @@ from pyclowder.utils import CheckMessage from Jim_ColorHistogram_ColorScatterPlot import image_analysis from optimizer import optimizer_get, optimizer_tell, optimizer_init +from printability import process_image #TODO, Docker ENV SCP_WEB_URL_BASE = 'http://host.docker.internal:5000/structural-color-printing/' @@ -47,12 +48,20 @@ def process_message(self, connector, host, secret_key, resource, parameters): number_prints_trigger_prediction = metadata['number_prints_trigger_prediction'] accum_h_mu = float(metadata['accum_h_mu']) + predict_ranges = metadata['predict_ranges'] + my_space = [(float(predict_ranges.get("min_speed")), float(predict_ranges.get("max_speed"))), + (float(predict_ranges.get("min_bed_temp")), float(predict_ranges.get("max_bed_temp"))), + (float(predict_ranges.get("min_pressure")), float(predict_ranges.get("max_pressure"))), + (float(predict_ranges.get("min_zheight")), float(predict_ranges.get("max_zheight")))] + + print(my_space) print("campaign_id", campaign_id) print("cell_id", cell_id) print('rank_run') print('number_prints_trigger_prediction') inputfile = pyclowder.files.download(connector, host, secret_key, resource['id']) H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig = image_analysis(inputfile) + printability_score = process_image(inputfile) content = { # 'H_DIST': H_DIST.to_json(), 'h_mu': h_mu, @@ -71,18 +80,20 @@ def process_message(self, connector, host, secret_key, resource, parameters): data = None if rank_run == 0: self.campaign_id = campaign_id - self.opt = optimizer_init() + self.opt = optimizer_init(my_space) if (rank_run +1) % number_prints_trigger_prediction == 0: accum_h_mu += h_mu h_mu = accum_h_mu/number_prints_trigger_prediction PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, + "printability_score": printability_score, "cell_color": content, "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight} else: data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, - 'rank_run': rank_run} + 'rank_run': rank_run, + "printability_score": printability_score} # if self.campaign_id is None or self.campaign_id != campaign_id: # self.campaign_id = campaign_id # self.opt = optimizer_init() diff --git a/optimizer.py b/optimizer.py index bd327d7..84f0dc7 100644 --- a/optimizer.py +++ b/optimizer.py @@ -39,9 +39,9 @@ def Objective(h_mu): 'ExperimentNumber': [] }) -def optimizer_init(): +def optimizer_init(my_space=space): # ----------------------BO framework - opt = Optimizer(dimensions=space, + opt = Optimizer(dimensions=my_space, base_estimator='gp', # indirect kernel selection n_initial_points=5, initial_point_generator='random', diff --git a/printability.py b/printability.py new file mode 100644 index 0000000..e3a0d38 --- /dev/null +++ b/printability.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +""" +Created on Mon Apr 7 12:34:34 2025 + +@author: jalom +""" + +import cv2 as cv +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd + + +# Mask the bottom region of the image to exclude the base or irrelevant parts +# @input: image: The image to be dealt +# bottom_percent: cut bottom part as only center matters +# @return: A mask (The cut bottom part) which is either black(0) or white (255) +def mask_bottom_region(image, bottom_percent=0.2): + height, width = image.shape[:2] + mask = np.ones((height, width), dtype=np.uint8) * 255 + bottom_height = int(height * bottom_percent) + mask[height - bottom_height:, :] = 0 + return mask + + +# Improved contour filtering with an area filter +# @input: contours: The list of contours that detected +# min_area: the default smallest contour +# @return: the contour with largest area +def getBiggestContourWithAreaFilter(contours, min_area=500): + filtered_contours = [c for c in contours if cv.contourArea(c) > min_area] + if len(filtered_contours) == 0: + return None + return max(filtered_contours, key=cv.contourArea) + + +# @input: binaryImage: The mask from previous func +# mode: way to get contour, set to default +# method: way to get points in contour +# @return: contour list used for getbiggest func +def getContours(binaryImage, mode='TREE', method=cv.CHAIN_APPROX_NONE): + try: + if mode == 'LIST': + contours, _ = cv.findContours(binaryImage, cv.RETR_CCOMP, method) + else: + contours, _ = cv.findContours(binaryImage, cv.RETR_TREE, method) + return contours + except Exception as e: + print(f"Error in getContours: {e}") + return None + + +# @input: the contour +# y value for the horizontal line +# @return: list of intersecting x value +def get_horizontal_intersections(contour, y_line): + # initialize the list to store all intersecting x value + intersections = [] + # usually in contour we have numpy with form (n,1,2) to store all points + # first : means that we pick all points within the contour + # 0 means we ignore second part + # third : means pick all (x,y) + pts = contour[:, 0, :] + num_points = pts.shape[0] + # iterate all points + for i in range(num_points): + p1 = pts[i] + p2 = pts[(i + 1) % num_points] # ensure the last point meets with the first one + y1, y2 = p1[1], p2[1] + # decide if the edge of two points will intersect with horizontal line + # proceed if the product < 0, indicating a valid intersection + if (y1 - y_line) * (y2 - y_line) < 0: + # calculate the x value of the intersection point + x = p1[0] + (y_line - y1) * (p2[0] - p1[0]) / (y2 - y1) + intersections.append(x) + # deal with case if both y1, y2 are on the line + elif y1 == y_line or y2 == y_line: + intersections.extend([p1[0], p2[0]]) + return intersections + + +# @input: image_file: the image we need to analyze +# bottom_percent: the percent that we want to mask at the beginning +# threshold_val: the threshold that we use to disguish between background and targe image. 50 TBD!!! +def process_image(image_file, bottom_percent=0.0, threshold_val=50): + # step 1: read image and mask bottom + img_bgr = cv.imread(image_file) + if img_bgr is None: + raise ValueError(f"Cannot read image: {image_file}") + bottom_mask = mask_bottom_region(img_bgr, bottom_percent=bottom_percent) + masked_bgr = cv.bitwise_and(img_bgr, img_bgr, mask=bottom_mask) + + # step 2: deal with the image and turn it into clear, simplified image + img_rgb = cv.cvtColor(masked_bgr, cv.COLOR_BGR2RGB) + gray_img = cv.cvtColor(img_rgb, cv.COLOR_RGB2GRAY) + _, bin_img = cv.threshold(gray_img, threshold_val, 255, cv.THRESH_BINARY) + + # step 3: detect and get the exact contour + contours = getContours(bin_img) + contour = getBiggestContourWithAreaFilter(contours, min_area=5000) + if contour is None: + raise ValueError("No valid contour found. Adjust threshold or check the image.") + + # step 4: get the coordinates of all points, especailly the upper and lower bound of y + pts = contour[:, 0, :] + topmost_y = np.min(pts[:, 1]) + bottommost_y = np.max(pts[:, 1]) + # calculate total height + total_height = bottommost_y - topmost_y + if total_height <= 0: + raise ValueError("Invalid contour height (possibly a single line?).") + + # From here we compute the height of each segment and get their according y values + # seg_height = total_height / (n + 1) + horizontal_lines = list(range(topmost_y, bottommost_y + 1)) + + # 5. For each horizontal line, get its all x values and draw the lines + line_lengths = [] + img_with_lines = img_rgb.copy() # copy of original image and we will modify on this version + + # iterate the horizontal height values and get the x values for each height y + for y in horizontal_lines: + xs = get_horizontal_intersections(contour, y) + # if the number of x values is smaller than 2, meaning it can not form a valid segment. So we label the length to be 0 + if len(xs) < 2: + line_lengths.append(0) + continue + # if it is a valid line, then we store it. + left_x, right_x = min(xs), max(xs) + line_length = right_x - left_x + line_lengths.append(line_length) + + # draw the line in red within range of the contour + cv.line( + img_with_lines, + (int(left_x), int(y)), + (int(right_x), int(y)), + (255, 0, 0), + 2 + ) + + # draw the exact contour(green) + cv.drawContours(img_with_lines, [contour], -1, (0, 255, 0), 3) + + # step 6: show the final score + + # plt.figure(figsize=(10, 8)) + # plt.imshow(img_with_lines) + # plt.title("Contour with Horizontal Segments Inside") + # plt.axis('off') + # plt.show() + + # 7. draw the histogram + # plt.figure(figsize=(12, 6)) + # indices = np.arange(len(horizontal_lines)) + # plt.bar(indices, line_lengths, color='skyblue', label='Segment Length') + # plt.xlabel("Horizontal Line Index (from bottom to top)") + # plt.ylabel("Length (pixels)") + # plt.title("Horizontal Intersection Lengths Within Contour") + + # Step 8: Calculate mean and standard deviation + lengths_array = np.array(line_lengths) + mean_length = np.mean(lengths_array) + std_length = np.std(lengths_array) # printability score t be saved + print(f"std_length: {std_length}") + return std_length + + # draw the line of average and standard deviation + # plt.axhline(mean_length, color='red', linestyle='--', linewidth=2, label=f'Mean = {mean_length:.2f}') + # # use fill_between to depict the sd + # plt.fill_between(indices, mean_length - std_length, mean_length + std_length, + # color='green', alpha=0.3, label=f'Std Dev = {std_length:.2f}') + # plt.legend() + # plt.show() + + # print out info of each segment + ## for test: print(f"Line length{total_height}") + # for idx, length in enumerate(line_lengths, start=1): + # print(f"Line {idx}: y = {horizontal_lines[idx-1]:.2f}, Length = {length:.2f} pixels") + # # Step 9: save the result as csv file + # df = pd.DataFrame({ + # 'y': horizontal_lines, + # 'length': line_lengths + # }) + # csv_filename = "segmentation_lengths.csv" + # df.to_csv(csv_filename, index=False) + # print(f"Results saved to {csv_filename}") +# change the file name and the number of inserction parts here +# if __name__ == "__main__": +# image_file = "Green_Sanghyun.jpg" +# process_image(image_file) \ No newline at end of file From df1609185ab269ee7e80943d0066d1954161a6e9 Mon Sep 17 00:00:00 2001 From: bingzhang Date: Fri, 1 Aug 2025 13:29:42 -0500 Subject: [PATCH 7/8] skip failed print --- image_analysis_extractor.py | 60 +++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index 386c057..22bff08 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -39,11 +39,14 @@ def check_message(self, connector, host, secret_key, resource, parameters): def process_message(self, connector, host, secret_key, resource, parameters): # get input file inputfile = None + is_success = True try: + print(f"resource: {resource}") file_id = resource['id'] metadata = resource['metadata'] campaign_id = metadata['campaign_id'] cell_id = metadata['cell_id'] + is_skip = bool(metadata['is_skip']) rank_run = metadata['rank_run'] number_prints_trigger_prediction = metadata['number_prints_trigger_prediction'] accum_h_mu = float(metadata['accum_h_mu']) @@ -60,8 +63,24 @@ def process_message(self, connector, host, secret_key, resource, parameters): print('rank_run') print('number_prints_trigger_prediction') inputfile = pyclowder.files.download(connector, host, secret_key, resource['id']) - H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig = image_analysis(inputfile) - printability_score = process_image(inputfile) + + printability_score = 100 + h_mu = 0 + h_sig = 0 + v_mu = 0 + v_sig = 0 + s_mu = 0 + s_sig = 0 + if is_skip: + is_success = False + else: + try: + H_DIST, h_mu, h_sig, V_DIST, v_mu, v_sig, S_DIST, s_mu, s_sig = image_analysis(inputfile) + printability_score = process_image(inputfile) + except: + is_success = False + traceback.print_exc() + content = { # 'H_DIST': H_DIST.to_json(), 'h_mu': h_mu, @@ -78,22 +97,31 @@ def process_message(self, connector, host, secret_key, resource, parameters): # upload metadata # pyclowder.files.upload_metadata(connector, host, secret_key, parameters['id'], metadata) data = None - if rank_run == 0: - self.campaign_id = campaign_id - self.opt = optimizer_init(my_space) - if (rank_run +1) % number_prints_trigger_prediction == 0: - accum_h_mu += h_mu - h_mu = accum_h_mu/number_prints_trigger_prediction - PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) - _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) - data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, - "printability_score": printability_score, - "cell_color": content, - "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight} + if is_success: + if rank_run == 0: + self.campaign_id = campaign_id + self.opt = optimizer_init(my_space) + if (rank_run +1) % number_prints_trigger_prediction == 0: + accum_h_mu += h_mu + h_mu = accum_h_mu/number_prints_trigger_prediction + combined_objective = h_mu * printability_score + PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) + _ = optimizer_tell(self.opt, combined_objective, PrintSpeed, BedTemp, Pressure, ZHeight) + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, + "printability_score": printability_score, + "cell_color": content, + "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight, + "is_success": True} + else: + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, + 'rank_run': rank_run, + "printability_score": printability_score, + "is_success": True} else: data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, - 'rank_run': rank_run, - "printability_score": printability_score} + 'rank_run': rank_run, + "printability_score": printability_score, + "is_success": False} # if self.campaign_id is None or self.campaign_id != campaign_id: # self.campaign_id = campaign_id # self.opt = optimizer_init() From c45c172da14868813b9afb2dbe6bb84defbf1157 Mon Sep 17 00:00:00 2001 From: Bing Zhang Date: Sun, 3 Aug 2025 14:45:22 -0500 Subject: [PATCH 8/8] handle failed prints --- image_analysis_extractor.py | 61 ++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/image_analysis_extractor.py b/image_analysis_extractor.py index 22bff08..5fa70d2 100644 --- a/image_analysis_extractor.py +++ b/image_analysis_extractor.py @@ -91,44 +91,37 @@ def process_message(self, connector, host, secret_key, resource, parameters): # 'S_DIST': S_DIST.to_json(), 's_mu': s_mu, 's_sig': s_sig} - # format the conent as a metadata - # metadata = self.get_metadata(content, "file", parameters['id'], host) - - # upload metadata - # pyclowder.files.upload_metadata(connector, host, secret_key, parameters['id'], metadata) data = None - if is_success: - if rank_run == 0: - self.campaign_id = campaign_id - self.opt = optimizer_init(my_space) - if (rank_run +1) % number_prints_trigger_prediction == 0: - accum_h_mu += h_mu - h_mu = accum_h_mu/number_prints_trigger_prediction - combined_objective = h_mu * printability_score - PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) - _ = optimizer_tell(self.opt, combined_objective, PrintSpeed, BedTemp, Pressure, ZHeight) - data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, - "printability_score": printability_score, - "cell_color": content, - "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight, - "is_success": True} - else: - data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, - 'rank_run': rank_run, - "printability_score": printability_score, - "is_success": True} - else: + try: + if is_success: + if rank_run == 0: + self.campaign_id = campaign_id + self.opt = optimizer_init(my_space) + if (rank_run +1) % number_prints_trigger_prediction == 0: + accum_h_mu += h_mu + h_mu = accum_h_mu/number_prints_trigger_prediction + combined_objective = h_mu * printability_score + PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) + _ = optimizer_tell(self.opt, combined_objective, PrintSpeed, BedTemp, Pressure, ZHeight) + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, 'rank_run': rank_run, + "printability_score": printability_score, + "cell_color": content, + "PrintSpeed": PrintSpeed, "BedTemp": BedTemp, "Pressure": Pressure, "ZHeight": ZHeight, + "is_success": True} + else: + data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, + 'rank_run': rank_run, + "printability_score": printability_score, + "is_success": True} + except: + is_success = False + traceback.print_exc() + if not is_success: data = {"campaign_id": campaign_id, "cell_id": cell_id, "file_id": file_id, "cell_color": content, 'rank_run': rank_run, "printability_score": printability_score, "is_success": False} - # if self.campaign_id is None or self.campaign_id != campaign_id: - # self.campaign_id = campaign_id - # self.opt = optimizer_init() - - # PrintSpeed, BedTemp, Pressure, ZHeight = optimizer_get(self.opt) - # _ = optimizer_tell(self.opt, h_mu, PrintSpeed, BedTemp, Pressure, ZHeight) - # store backt tp SCP web application + # store backt to SCP web application try: url = SCP_WEB_URL_BASE + 'campaign/%s/update_cell_color' % (campaign_id) result = requests.post(url, data=json.dumps(data), @@ -146,4 +139,4 @@ def process_message(self, connector, host, secret_key, resource, parameters): if __name__ == "__main__": extractor = ImageAnalysisExtractor() - extractor.start() + extractor.start() \ No newline at end of file