This commit is contained in:
alexgobbo
2024-09-17 18:10:45 +02:00
parent 93f0c812e7
commit 0692cd7cdc
11 changed files with 575 additions and 25 deletions

View File

@@ -1,3 +1,4 @@
Image_Correlator.java=enabled
MXSC-1.14.0.jar=disabled
MXSC-1.15.0.jar=disabled
Commands.java=disabled

View File

@@ -1,4 +1,4 @@
#Fri Sep 13 09:52:22 CEST 2024
#Tue Sep 17 18:09:54 CEST 2024
barcode_reader_scan_pucks=false
beamline_status_enabled=false
cold_position_timeout=3600

View File

@@ -1,3 +1,4 @@
tasks/LedMonitoring=120.0;120.0
tasks/ColdPositionTimeout=300.0;300.0
#tasks/Reinit=30.0;30.0
#test/TestCorrelation=1.0;1.0

View File

@@ -1,4 +1,4 @@
#Fri Sep 13 10:02:48 CEST 2024
#Tue Sep 17 18:09:58 CEST 2024
center_x=820.0
center_y=570.0
continuous=false
@@ -6,3 +6,4 @@ modulo=3
number_images=2
scale_x=0.3
scale_y=0.3
threshold=0.6

View File

@@ -0,0 +1,220 @@
import java.awt.*;
import java.io.*;
import ij.*;
import ij.gui.*;
import ij.process.*;
import ij.text.*;
import ij.plugin.PlugIn;
//This plugin correlates two 8-bit images or stacks. The resultant correlation plot is a
//stack with the same number of slices as the stack with the fewer number.
//Many correlation plots need to be recontrasted. Pressing Apple/Shift/C will
//bring up the Brightness/Contrast menu.
public class Image_Correlator implements PlugIn {
private static int index1;
private static int index2;
private static boolean displayCounts, collate;
private ImageStack img1, img2;
private int smallest;
private int z1, z2, count;
public void run(String arg) {
if (showDialog())
correlate(img1, img2);
}
public boolean showDialog() {
int[] wList = WindowManager.getIDList();
if (wList==null) {
IJ.noImage();
return false;
}
String[] titles = new String[wList.length];
for (int i=0; i<wList.length; i++) {
ImagePlus imp = WindowManager.getImage(wList[i]);
if (imp!=null)
titles[i] = imp.getTitle();
else
titles[i] = "";
}
if (index1>=titles.length)index1 = 0;
if (index2>=titles.length)index2 = 0;
GenericDialog gd = new GenericDialog("Image Correlator");
gd.addChoice("Image1: ", titles, titles[index1]);
gd.addChoice("Image2: ", titles, titles[index2]);
gd.addCheckbox("Display Counts: ", displayCounts);
gd.addCheckbox("Collate Z-Data (Stacks Only):", collate);
gd.showDialog();
if (gd.wasCanceled())
return false;
index1 = gd.getNextChoiceIndex();
index2 = gd.getNextChoiceIndex();
displayCounts = gd.getNextBoolean();
collate = gd.getNextBoolean();
String title1 = titles[index1];
String title2 = titles[index2];
//Test to find out if both images are 8-bit grayscale.
ImagePlus sliceimg1 = WindowManager.getImage(wList[index1]);
ImagePlus sliceimg2 = WindowManager.getImage(wList[index2]);
if (sliceimg1.getType()!=sliceimg1.GRAY8 || sliceimg2.getType()!=sliceimg1.GRAY8) {
IJ.showMessage("Image Correlator", "Both stacks must be 8-bit grayscale.");
return false;
}
img1 = sliceimg1.getStack();
img2 = sliceimg2.getStack();
return true;
}
public Object[] getCorrelation(ImagePlus im1, ImagePlus im2){
int width = im1.getWidth();
int height = im1.getHeight();
float[] v1, v2;
ip1 = im1.getProcessor();
ip2 = im2.getProcessor();
v1 = new float[width*height];
v2 = new float[width*height];
ImageProcessor plot= new FloatProcessor(256, 256);
int index = 0;
for (int y=0; y<height; y++) {//Loop for Y-Values
for (int x=0; x<width; x++) {//Loop for X-Values
z1 = (int)ip1.getPixelValue(x,y); // z-value of pixel (x,y)in stack #1 on slice s
z2 = (int)ip2.getPixelValue(x,y); // z-value of pixel (x,y)in stack #2 on slice s
v1[index] = z1;
v2[index] = z2;
z2 = 255 - z2;
index++;
count = (int)plot.getPixelValue(z1, z2);
count++;
plot.putPixelValue(z1, z2, count);
}
}
plot.invertLut();
plot.resetMinAndMax();
pcc = calculateCorrelation(v1, v2);
ImagePlus ret = new ImagePlus("Correlation Plot", plot);
return new Object[]{pcc,ret};
}
public void correlate(ImageStack img1, ImageStack img2) {
int size1 = img1.getSize();
int size2 = img2.getSize();
boolean unsigned = true;
//Finds out which stack has fewer slices and sets it to be the
//number of slices in the correlation plot
if (size1<=size2)
smallest = size1;
if (size2<size1)
smallest = size2;
int width = img1.getWidth();
int height = img1.getHeight();
float[] v1, v2;
ImageStack stackplot = new ImageStack(256, 256);
ImageProcessor ip1, ip2, plot=null;
double pcc=0;
for(int i=1; i<=smallest; i++) {
ip1 = img1.getProcessor(i);
ip2 = img2.getProcessor(i);
v1 = new float[width*height];
v2 = new float[width*height];
if (i==1 || !collate)
plot = new FloatProcessor(256, 256);
int index = 0;
for (int y=0; y<height; y++) {//Loop for Y-Values
for (int x=0; x<width; x++) {//Loop for X-Values
z1 = (int)ip1.getPixelValue(x,y); // z-value of pixel (x,y)in stack #1 on slice s
z2 = (int)ip2.getPixelValue(x,y); // z-value of pixel (x,y)in stack #2 on slice s
v1[index] = z1;
v2[index] = z2;
z2 = 255 - z2;
index++;
count = (int)plot.getPixelValue(z1, z2);
count++;
plot.putPixelValue(z1, z2, count);
}
}
plot.invertLut();
plot.resetMinAndMax();
pcc = calculateCorrelation(v1, v2);
if (i==1 || !collate)
stackplot.addSlice(IJ.d2s(pcc,6), plot);
IJ.showProgress((double)i/smallest);
IJ.showStatus("Correlating slice: "+ i +"/" + smallest);
}
IJ.showProgress(1.0);
ImagePlus imp2 = new ImagePlus("Correlation Plot", stackplot);
if (smallest==1)
imp2.setTitle("Plot ("+IJ.d2s(pcc,6)+")");
imp2.show();
IJ.run("Enhance Contrast", "saturated=0.5");
if (displayCounts)
displayCounts(stackplot);
}
// http://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient
double calculateCorrelation(float[] x, float[] y) {
double sumx = 0;
double sumy = 0;
int n = x.length;
for (int i=0; i<n; i++) {
sumx += x[i];
sumy += y[i];
}
double xmean = sumx/n;
double ymean = sumy/n;
double sum = 0;
for (int i=0; i<n; i++)
sum += (x[i]-xmean)*(y[i]-ymean);
double sumx2 = 0;
for (int i=0; i<n; i++)
sumx2 += sqr(x[i]-xmean);
double sumy2 = 0;
for (int i=0; i<n; i++)
sumy2 += sqr(y[i]-ymean);
return sum/(Math.sqrt(sumx2)*Math.sqrt(sumy2));
}
double sqr(double x) {
return x*x;
}
boolean isStack(ImageStack i1, ImageStack i2){
if ((i1.getSize()>1) && (i2.getSize()>1))
return true;
else
return false;
}
void displayCounts(ImageStack plot) {
StringBuffer sb = new StringBuffer();
int count;
int slices = plot.getSize();
if (slices==1) {
ImageProcessor ip = plot.getProcessor(1);
for (int x=0; x<256; x++)
for (int y=255; y>=0; y--) {
count = (int)ip.getPixelValue(x,y);
if (count>0)
sb.append(x+"\t"+(255-y)+"\t"+count+"\n");
}
new TextWindow("Non-zero Counts" , "X\tY\tCount", sb.toString(), 300, 400);
} else {
for (int slice=1; slice<=slices; slice++) {
ImageProcessor ip = plot.getProcessor(slice);
for (int x=0; x<256; x++)
for (int y=255; y>=0; y--) {
count = (int)ip.getPixelValue(x,y);
if (count>0)
sb.append(x+"\t"+(255-y)+"\t"+(slice-1)+"\t"+count+"\n");
}
}
new TextWindow("Non-zero Counts" , "X\tY\tZ\tCount", sb.toString(), 300, 400);
}
}
}

View File

@@ -1,4 +1,5 @@
run("imgproc/NewCoverDetection")
run("imgproc/NewCoverCorrelation")
class CoverDetectionConfig(RegisterConfig):
@@ -10,7 +11,16 @@ class CoverDetectionConfig(RegisterConfig):
self.center_y = 570.0
self.scale_x = 1.0
self.scale_y = 1.0
self.scale_y = 1.0
self.threshold = 0.60
class CoverCorrelation(ReadonlyAsyncRegisterBase):
def __init__(self, name):
ReadonlyAsyncRegisterBase.__init__(self, name)
def set(self, value):
self.onReadout(value)
class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
def __init__(self, name, image):
@@ -32,13 +42,21 @@ class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
self.error_overlay=None
self.img_counter, self.proc_counter = 0, 0
self.offset_px = self.offset_um = None
self.correlation = CoverCorrelation("cover_correlation")
self.correlation_error = False
def doInitialize(self):
self.enable()
self.clear()
try:
self.enable()
self.clear()
#self.grab_ref_image()
except:
traceback.print_exc()
raise
def doClose(self):
self.disable()
def doClose(self):
self.disable()
self.correlation.close()
def set_renderer(self, renderer):
self.clear()
@@ -60,7 +78,8 @@ class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
def clear(self):
self.set_marker(None)
self.set_error_overlay(None)
self.set_error_overlay(None)
self.set_correlation(None)
def append(self, image):
self.img_counter += 1
@@ -83,7 +102,20 @@ class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
x,y = -1, -1
self.processing_time = time.time()-start
self.proc_counter += 1
try:
corr = get_correlation(ip.getBufferedImage())
self.correlation.set(corr)
self.set_correlation(corr)
except Exception as e:
#traceback.print_exc()
if self.error is None:
self.error = e
self.set(x, y, self.processing_time * 1000, self.error)
#traceback.print_exc()
if not self.config.continuous:
self.images=[]
@@ -96,7 +128,7 @@ class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
offx, offy = x-cover_detection.config.center_x, -(y-cover_detection.config.center_y)
self.offset_px = opx, opy = round(offx), round(offy)
self.offset_um = omx, omy = self.config.scale_x * offx * 1000.0, self.config.scale_y * offy *1000.0
value = to_array([x, y, opx, opy, omx, omy, tm], 'i')
value = to_array([x, y, opx, opy, omx, omy, tm], 'i')
self.onReadout(value)
if self.renderer is not None:
if error is None:
@@ -122,8 +154,35 @@ class CoverDetection(ReadonlyAsyncRegisterBase, ReadonlyRegisterArray):
self.error_overlay = error_overlay
else:
self.error_overlay = None
def grab_ref_image(self):
if self.config.number_images>1:
images = []
for i in range(self.config.number_images):
ip = load_image(ImagingUtils.grayscale(self.image.output, None))
images.append(ip)
self.image.waitNext(-1)
ip = integrate(images)
img = ip.getBufferedImage()
else:
img = self.image.output
save_ref_img(img)
def set_correlation(self, corr):
self.corr = corr
error = corr is not None and corr < self.config.threshold
if error != self.correlation_error:
self.correlation_error = error
if error:
print ("Image anomally detected")
else:
print ("Image ok")
if error:
raise Exception ("Image anomally detected")
add_device(CoverDetection("cover_detection", image), force = True)
add_device(cover_detection.correlation, force = True)
renderer=show_panel(image)
cover_detection.set_renderer(renderer)

View File

@@ -55,16 +55,15 @@ class VmbCamera (CameraBase):
fork(init_img)
self.setState(State.Disabled)
def add_img_device(self):
def add_dev_task():
def add_initialized_callback(self, callback):
def wait_init():
try:
self.waitStateNot(State.Disabled, -1)
if (self.stream.state == State.Busy) and (get_context().state.isActive()):
add_device(self.image, True)
log("Added VmbCamera image device")
callback()
except Exception as e:
log(str(e))
fork(add_dev_task)
fork(wait_init)
def getInfo(self):
try:
@@ -282,6 +281,10 @@ fork(start_camera_server)
c = VmbCamera("cam", image_name="image")
add_device(c, True)
add_device(c.stream, True)
c.add_img_device()
def initialized_callback():
add_device(c.image, True)
add_device(c.image.contrast, force = True)
log("Added VmbCamera image device")
run( "devices/CoverDetection")
c.add_initialized_callback(initialized_callback)

View File

@@ -0,0 +1,99 @@
import ch.psi.pshell.imaging.ImageBuffer as ImageBuffer
offset = 0
add_mark = False
#offset = 50
#add_mark = True
Image_Correlator = get_context().getClassByName("Image_Correlator")
correlator = Image_Correlator()
def get_min(ip1):
return ip1.getProcessor().getStatistics().min
def mean_abs_error(ip1, ip2):
sum = 0.0
for y in range(ip1.getHeight()):
for x in range(ip1.getWidth()):
p1 = ip1.getPixel(x, y)
p2 = ip2.getPixel(x, y)
sum += abs(p1 - p2)
return sum / (ip1.height * ip1.width )
def rms_error(ip1, ip2):
sum = 0.0
for y in range(ip1.getHeight()):
for x in range(ip1.getWidth()):
p1 = ip1.getPixel(x, y)
p2 = ip2.getPixel(x, y)
sum += math.pow((p1 - p2),2)
return sum / (ip1.height * ip1.width )
def get_roi_img(img, img_size=1024, radius=512, offset_x=0, offset_y=0):
x,y,w,h = int(cover_detection.config.center_x-img_size/2 + offset_x), \
int(cover_detection.config.center_y-img_size/2 + offset_y), \
img_size, img_size
roi = ImagingUtils.copy(img, None, Rectangle(x,y,w,h))
ip = load_image(roi, title="Img")
p = ip.getProcessor()
mask = p.createProcessor(roi.getWidth(), roi.getHeight())
mask.setColor(255)
cx, cy = img_size/2 - offset_x, img_size/2 - offset_y
mask.fillOval(int(cx - radius), int(cy - radius), int(2 * radius), int(2 * radius)) # Draw the circular ROI
mask.autoThreshold() # Ensures the mask is binary (if needed)
p.copyBits(mask, 0, 0, Blitter.AND) # Apply the mask using a bitwise AND
#gaussian_blur(ip)
p.blurGaussian(1.0)
return ip.getBufferedImage()
def get_edge_img(ib):
ed = ImagingUtils.edgeDetect(ib)
ret = load_image(ed, title="Refe")
#auto_threshold(ret, dark_background=True)
#binary_dilate(ret, iterations=1, count=1)
return ret
def save_ref_img(img):
path = os.path.abspath(expand_path("{images}/ip_ref_fe.png"))
roi=get_roi_img(img, offset_x=0, offset_y=0)
ImageBuffer.saveImage(roi, path, "png")
#ip_ref = load_image(roi, title="ip_ref")
#save_image(ip_ref, path ,"png")
#$ImagingUtils.
#ip_ref_e =get_edge_img(roi)
#save_image(ip_ref_e, path+"ip_ref_e.png" ,"png")
##ip_ref_f = image_fft(ip_ref)
#ip_ref_fe = image_fft(ip_ref_e)
#save_image(ip_ref_fe, path+"ip_ref_fe.png" ,"png")
def put_mark(ib):
for x in range(450, 470):
for y in range(450, 470):
ib.setRGB(x,y, 0)
def get_correlation(img):
global ip_ref_fe
if "ip_ref_fe" not in globals() or ip_ref_fe is None:
path = os.path.abspath(expand_path("{images}/ip_ref_fe.png"))
roi = ImagingUtils.newImage(path)
#ip_ref_fe=open_imagroie(path+"ip_ref_fe.png" ,"png")
#ip_ref = load_image(roi, title="ip_ref")
ip_ref_e =get_edge_img(roi)
ip_ref_fe = image_fft(ip_ref_e)
print "Opend reference image"
roi =get_roi_img(img, offset_x=-offset, offset_y=-offset)
if add_mark:
put_mark(roi)
#ip_cur = load_image(roi, title="Ref")
ip_cur_e =get_edge_img(roi)
#ip_cur_f = image_fft(ip_cur)
ip_cur_fe = image_fft(ip_cur_e)
return correlator.getCorrelation(ip_ref_fe, ip_cur_fe)[0]

View File

@@ -110,9 +110,12 @@ set_setting(BEAMLINE_STATUS_ENABLED_PREFERENCE, is_beamline_status_enabled())
###################################################################################################
# Scripted devices and pseudo-devices
###################################################################################################
scripted_devices = ["devices/RobotSC", "devices/Wago", "devices/BarcodeReader", "devices/LaserDistance",
"devices/LedCtrl", "devices/SmartMagnet", "devices/Gonio", "devices/VmbCamera" #"devices/HexiPosi"]"
"devices/LedCtrl", "devices/SmartMagnet", "devices/Gonio", #"devices/HexiPosi"]"
"devices/VmbCamera",
]
for script in scripted_devices:
@@ -122,12 +125,6 @@ for script in scripted_devices:
run(script)
except:
print >> sys.stderr, traceback.format_exc()
#if is_imaging_enabled():
if get_device("img") is not None:
add_device(img.getContrast(), force = True)

View File

@@ -0,0 +1,129 @@
show = False
img_size = 1024
RADIUS = 512
FRAMES = 1
offset = 0
add_mark = False
#offset = 50
#add_mark = True
Image_Correlator = get_context().getClassByName("Image_Correlator")
correlator = Image_Correlator()
def get_roi_img(radius, offset_x=0, offset_y=0, frames=1):
x,y,w,h = int(cover_detection.config.center_x-img_size/2 + offset_x), \
int(cover_detection.config.center_y-img_size/2 + offset_y), \
img_size, img_size
if frames>1:
ip = integrate_frames(samples = frames)
roi = ImagingUtils.copy(ip.getBufferedImage(), None, Rectangle(x,y,w,h))
else:
roi = ImagingUtils.copy(image.output, None, Rectangle(x,y,w,h))
ip = load_image(roi, title="Img")
p = ip.getProcessor()
mask = p.createProcessor(roi.getWidth(), roi.getHeight())
mask.setColor(255)
cx, cy = img_size/2 - offset_x, img_size/2 - offset_y
mask.fillOval(int(cx - radius), int(cy - radius), int(2 * radius), int(2 * radius)) # Draw the circular ROI
mask.autoThreshold() # Ensures the mask is binary (if needed)
p.copyBits(mask, 0, 0, Blitter.AND) # Apply the mask using a bitwise AND
#gaussian_blur(ip)
p.blurGaussian(1.0)
return ip.getBufferedImage()
def get_edge_img(ib):
ed = ImagingUtils.edgeDetect(ib)
ret = load_image(ed, title="Refe")
#auto_threshold(ret, dark_background=True)
#binary_dilate(ret, iterations=1, count=1)
return ret
def put_mark(ib):
for x in range(450, 470):
for y in range(450, 470):
ib.setRGB(x,y, 0)
def load_ref_img(reload = False, frames=FRAMES):
global ip_ref, ip_ref_e, ip_ref_f, ip_ref_fe
if reload or "ip_ref_fe" not in globals():
print "Loading cover reference image"
roi =get_roi_img(RADIUS, 0, 0, frames)
ip_ref = load_image(roi, title="Ref")
ip_ref_e =get_edge_img(roi)
ip_ref_f = image_fft(ip_ref)
ip_ref_fe = image_fft(ip_ref_e)
load_ref_img()
def load_cur_img(frames=FRAMES):
global ip_cur, ip_cur_e, ip_cur_f, ip_cur_fe
roi =get_roi_img(RADIUS, -offset, -offset, frames)
if add_mark:
put_mark(roi)
ip_cur = load_image(roi, title="Ref")
ip_cur_e =get_edge_img(roi)
ip_cur_f = image_fft(ip_cur)
ip_cur_fe = image_fft(ip_cur_e)
load_cur_img()
#show_panel(ip1e.getBufferedImage())
#show_panel(ip2e.getBufferedImage())
coef_img, _ = correlator.getCorrelation(ip_ref, ip_cur)
coef_ed, _ = correlator.getCorrelation(ip_ref_e, ip_cur_e)
coef_fft, _ = correlator.getCorrelation(ip_ref_f, ip_cur_f)
coef_ffte, _ = correlator.getCorrelation(ip_ref_fe, ip_cur_fe)
#show_panel(sub1)
#sub = ImagingUtils.sub(BufferedImage, BufferedImage, boolean)
#sub = load_image(sub, title="sub")
#sube = load_image(sube, title="sube")
if show:
st=create_stack([ip_ref, ip_cur, ip_ref_e, ip_cur_e, ip_ref_f, ip_cur_f, ip_ref_fe, ip_cur_fe])
st.show()
def get_min(ip1):
return ip1.getProcessor().getStatistics().min
def mean_abs_error(ip1, ip2):
sum = 0.0
for y in range(ip1.getHeight()):
for x in range(ip1.getWidth()):
p1 = ip1.getPixel(x, y)
p2 = ip2.getPixel(x, y)
sum += abs(p1 - p2)
return sum / (ip1.height * ip1.width )
def rms_error(ip1, ip2):
sum = 0.0
for y in range(ip1.getHeight()):
for x in range(ip1.getWidth()):
p1 = ip1.getPixel(x, y)
p2 = ip2.getPixel(x, y)
sum += math.pow((p1 - p2),2)
return sum / (ip1.height * ip1.width )
mean_err, mean_erre = mean_abs_error(ip_ref_f.getProcessor(), ip_cur_f.getProcessor()), mean_abs_error(ip_ref_fe.getProcessor(), ip_cur_fe.getProcessor())
rms_err, rms_erre = rms_error(ip_ref_f.getProcessor(), ip_cur_f.getProcessor()), rms_error(ip_ref_fe.getProcessor(), ip_cur_fe.getProcessor())
if show:
#print offset, coef_img, coef_ed, coef_fft, coef_ffte
print coef_fft, coef_ffte
print mean_err, mean_erre
print rms_err, rms_erre

View File

@@ -0,0 +1,40 @@
class CoefFFT(ReadonlyRegisterBase):
def doRead(self):
return coef_fft
add_device(CoefFFT(), True)
CoefFFT.polling=1000
class CoefFFTE(ReadonlyRegisterBase):
def doRead(self):
return coef_ffte
add_device(CoefFFTE(), True)
CoefFFTE.polling=1000
class MeanErr(ReadonlyRegisterBase):
def doRead(self):
return mean_err
add_device(MeanErr(), True)
MeanErr.polling=1000
class MeanErrE(ReadonlyRegisterBase):
def doRead(self):
return mean_erre
add_device(MeanErrE(), True)
MeanErrE.polling=1000
class RmsErr(ReadonlyRegisterBase):
def doRead(self):
return rms_err
add_device(RmsErr(), True)
RmsErr.polling=1000
class RmsErrE(ReadonlyRegisterBase):
def doRead(self):
return rms_erre
add_device(RmsErrE(), True)
RmsErrE.polling=1000
#print coef_fft, coef_ffte
#print mean_err, mean_erre
#print rms_err, rms_erre