Hello Robin,
That is really not easy (for me).
I tried with different mathematical libraries ... but an array is a list and used () or {} or [] but not from Array type.
I searched fast everywhere, but I do not find what I wish. Sometimes I found an "add" function, but it is not a number addition, but a list concatenation.
Here my code. It can generate an average image. But the full array iteration in Python is relatively slow.
Code: Select all
# *******************************************************************************************
# SharpCap script "xxxxxxxxx.py"
# 2024/08/18 Jean-Francois
#
# Version: 1.0.0: First version
#
# The script works only with a SharpCap PRO version.
# *******************************************************************************************
import os
import time
import datetime
import math
import ctypes
import clr
clr.AddReference("Oxyplot")
clr.AddReference("OxyPlot.WindowsForms ")
clr.AddReference("System.Drawing")
clr.AddReference("System.Windows.Forms")
import OxyPlot
import System.Drawing
import System.Windows.Forms
from SharpCap.Base import BufferFrame
from System import Array
from System.Drawing import *
from System.Windows.Forms import *
from System.Threading import Thread, ApartmentState, ParameterizedThreadStart
i = 1
T_meas = []
W_meas = []
t0 = 0
image = 0
frameAverage = Array.CreateInstance(System.Double, 300 * 300)
frameAverage_byte = Array.CreateInstance(System.Byte, 300 * 300)
frameB = 0
pos = 0
# .ToBytes() (8 bit) .ToUshorts() (16 bit) and .ToFloats()
# BufferFrame.CopyFrom...()
#dll=ctypes.CDLL(dllfile)
def framehandler(sender, args):
global i, T_meas, W_meas, t0, frameAverage, pos, frameB
if (dumpdata):
try:
dt = (datetime.datetime.now() - t0).total_seconds()
cutout = args.Frame
Stat = cutout.GetStats()
T_meas.append(dt)
W_meas.append(Stat.Item1)
i = i + 1
frameB = cutout.ToUshorts() # 1D array
for index in range(frameB.Length):
frameAverage[index] += frameB[index]
# info = cutout.Info
# bufsize = int(cutout.BufferSize)
# lease = cutout.GetBufferLease()
# frameData_addr = lease.Buffer.ToInt64()
# frameData_ptr = ctypes.cast(frameData_addr, ctypes.POINTER(ctypes.c_ubyte))
# #dll.do_foo(frameData_ptr, info.Width, info.Height, bufsize)
# lease.Dispose()
except:
print("Problem")
# *****************************************************************************
def WIN_measurement(self):
global dumpdata
global i, T_meas, W_meas, t0, frameAverage
self.WIN_Monitoring.Text = "Monitoring running"
self.WIN_Monitoring.BackColor = Color.Red
self.WIN_Monitoring.Enabled = False
SharpCap.Transforms.SelectionRect = Rectangle(300, 300,600, 600)
i = 1
T_meas = []
W_meas = []
expos_ms = SharpCap.SelectedCamera.Controls.Exposure.ExposureMs
wait_time = 0.1 # waiting time between 2 refresh of Oxyplot graphic
print("Waiting Time: %5.3f" % (wait_time))
print()
print("WIN Transmission:")
print("******************")
dumpdata = True
SharpCap.SelectedCamera.FrameCaptured += framehandler
try:
if (float(self.textBoxTime.Text) > 0.0):
Max_time = float(self.textBoxTime.Text) - wait_time
t0 = datetime.datetime.now()
dt = 0
while (dt < Max_time):
dt = (datetime.datetime.now() - t0).total_seconds()
time.sleep(wait_time)
self.ShowOxyGraphic()
print("Time:", T_meas)
print("WIN:", W_meas)
print()
i = i - 1
print("Number: ", i)
mean = sum(W_meas) / len(W_meas)
var = sum(pow(x-mean,2) for x in W_meas) / len(W_meas)
std = math.sqrt(var)
print("Standard deviation 1: " + str("%.6f" % round(std,6)))
else:
print("Measurement time need to be larger than 0 s")
except:
print("Problem 1")
dumpdata = False
SharpCap.SelectedCamera.FrameCaptured -= framehandler
for index in range(frameAverage.Length):
frameAverage[index] = frameAverage[index] / i
try:
for index in range(frameAverage.Length):
frameAverage_byte[index] = frameAverage[index] / 256
flag = Bitmap(300,300)
for i in range(300):
for j in range(300):
index = i + (j * 300)
value = frameAverage_byte[index]
flag.SetPixel(i, j, System.Drawing.Color.FromArgb(value, value, value))
view.pictureBox1.Image = flag
except:
print()
print("picture problem")
print()
print("Show Average")
print()
print("Measurement done")
self.WIN_Monitoring.Text = "Start Measurement"
self.WIN_Monitoring.BackColor = Color.Gainsboro
self.WIN_Monitoring.Enabled = True
file_path = os.path.dirname(__file__)
file_name = file_path + "\\" + self.textBoxFileName.Text + ".txt"
file = open(file_name, "w")
for index in range(len(T_meas)):
file.write(str("%.4f" % T_meas[index]) + " " + str("%.4f" % W_meas[index]) + "\n")
file.close()
return()
# *****************************************************************************
class MonitoringWINMenuForm(Form):
def __init__(self):
self.SuspendLayout()
self.InitializeComponent()
self.setupCheckButtons()
self.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
self.AutoScaleDimensions = SizeF(96, 96)
self.ResumeLayout()
def InitializeComponent(self):
self.Text = "WIN Transmission"
self.ClientSize = System.Drawing.Size(700, 400)
self.TopMost = True
self.labelTime = Label()
self.textBoxTime = TextBox()
self.labelFile = Label()
self.textBoxFileName = TextBox()
self.plot1 = OxyPlot.WindowsForms.PlotView()
self.plot1.Location = System.Drawing.Point(10, 35)
self.plot1.Size = System.Drawing.Size(680, 350)
self.plot1.AutoSize = True
self.Controls.Add(self.labelTime)
self.Controls.Add(self.textBoxTime)
self.Controls.Add(self.labelFile)
self.Controls.Add(self.textBoxFileName)
self.Controls.Add(self.plot1)
self.labelTime.AutoSize = True
self.labelTime.Location = Point(150, 14)
self.labelTime.Name = "labelTime"
self.labelTime.Text = "Measurement time [s]:"
self.textBoxTime.AutoSize = True
self.textBoxTime.Location = Point(280, 13)
self.textBoxTime.Name = "textBoxTime"
self.textBoxTime.Size = Size(35, 20)
self.textBoxTime.Text = "1"
self.labelFile.AutoSize = True
self.labelFile.Location = Point(320, 14)
self.labelFile.Name = "labelFile"
self.labelFile.Text = "File:"
self.textBoxFileName.AutoSize = True
self.textBoxFileName.Location = Point(350, 13)
self.textBoxFileName.Name = "textBoxFileName"
self.textBoxFileName.Size = Size(250, 20)
self.textBoxFileName.Text = "test"
def setupCheckButtons(self):
self.WIN_Monitoring = Button()
self.WIN_Monitoring.Text = "Start Measurement"
self.WIN_Monitoring.Location = Point(20, 10)
self.WIN_Monitoring.Click += self.WIN_monitor
self.WIN_Monitoring.AutoSize = True
self.button_Exit = Button()
self.button_Exit.Text = "Exit"
self.button_Exit.Location = Point(615, 10)
self.button_Exit.Click += self.exit
self.button_Exit.AutoSize = True
self.Controls.Add(self.WIN_Monitoring)
self.Controls.Add(self.button_Exit)
def ShowOxyGraphic(self):
global T_meas, W_meas
self.plotmodel1 = OxyPlot.PlotModel()
self.YAxis1 = OxyPlot.Axes.LinearAxis(Position = OxyPlot.Axes.AxisPosition.Left, Minimum = 0.999*min(W_meas), Maximum = 1.001*max(W_meas))
self.points_start = []
for i in range(0,len(T_meas)):
self.points_start.Add(OxyPlot.DataPoint(T_meas[i],W_meas[i]))
self.serie_1 = OxyPlot.Series.LineSeries()
self.serie_1.Color = OxyPlot.OxyColors.Blue
self.serie_1.MarkerSize = 2
self.serie_1.MarkerType = OxyPlot.MarkerType.Circle
self.serie_1.StrokeThickness = 1
self.serie_1.ItemsSource = self.points_start
self.plotmodel1.Axes.Add(self.YAxis1)
self.plotmodel1.Series.Add(self.serie_1)
self.plot1.Model = self.plotmodel1
def WIN_monitor(self, sender, event):
th = Thread(ParameterizedThreadStart(WIN_measurement))
th.SetApartmentState(ApartmentState.STA)
th.Start(self)
def exit(self, sender, event):
print("Stop Monitoring script")
self.Close()
class MainForm(Form):
def __init__(self):
self.InitializeComponent()
self.pen = System.Drawing.Pen(System.Drawing.Color.Black);
def InitializeComponent(self):
self.pictureBox1 = System.Windows.Forms.PictureBox()
self.SuspendLayout()
self.pictureBox1.Location = System.Drawing.Point(3, 3)
self.pictureBox1.Name = "pictureBox1"
self.pictureBox1.Size = System.Drawing.Size(300, 300)
self.pictureBox1.TabIndex = 0
self.pictureBox1.TabStop = False
self.ClientSize = System.Drawing.Size(306, 306)
self.Controls.Add(self.pictureBox1)
self.Name = "MainForm"
self.Text = "Average"
self.ResumeLayout()
form = MonitoringWINMenuForm()
form.StartPosition = FormStartPosition.CenterScreen
form.TopMost = True
form.Show()
view = MainForm()
view.StartPosition = FormStartPosition.CenterScreen
view.TopMost = True
view.Show()
If somebody want to test:
- select the Test Camera 2 (Hight Speed)
- ROI = 300 x 300
- 16 bit mono
- 1 or 2 ms exposure with gain = 4000
- add noise on the image ~ 50
The code does not change the size or accept other image parameters.
One error can produce a crash of SharpCap.
Here an example of the result:

- cutout_average.jpg (196.9 KiB) Viewed 3151 times
On my computer, with the settings like above, SharpCap generates ~333 image/s.
If I disable the image average, then my script can calculate ~ 325 image/s.
If I activate the image average, the script calculates only ~ 41 image/s.
I really need to improve the calculation time of the image average.
I found somewhere in the forum under "script" topics ...
Code: Select all
dll=ctypes.CDLL(dllfile)
info = cutout.Info
bufsize = int(cutout.BufferSize)
lease = cutout.GetBufferLease()
frameData_addr = lease.Buffer.ToInt64()
frameData_ptr = ctypes.cast(frameData_addr, ctypes.POINTER(ctypes.c_ubyte))
#dll.do_foo(frameData_ptr, info.Width, info.Height, bufsize)
lease.Dispose()
It will be painful to code a dll in C/C++ for doing the calculation.
What is missing (I search, but I do not find a solution) is how to find the address of the Array().
Regards,
Jean-Francois