Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Micro-Manager
XenethCamera
Commits
29f6cb28
Commit
29f6cb28
authored
Jun 01, 2021
by
Rossa, Lutz
Browse files
put camera handling into background thread, fix some compiler warnings
parent
3ecf37a8
Changes
2
Hide whitespace changes
Inline
Side-by-side
XenethCamera.cpp
View file @
29f6cb28
...
@@ -133,6 +133,10 @@ XenethCamera::XenethCamera() :
...
@@ -133,6 +133,10 @@ XenethCamera::XenethCamera() :
m_byPixelSize
(
1
),
m_byPixelSize
(
1
),
m_szCameraPath
(
"cam://default"
),
m_szCameraPath
(
"cam://default"
),
m_lExposurePropertyIndex
(
-
1
),
m_lExposurePropertyIndex
(
-
1
),
m_bDoCameraThread
(
false
),
m_pCameraThread
(
nullptr
),
m_byCameraTrigger
(
0
),
m_iLastCameraResult
(
DEVICE_OK
),
m_uRoiX
(
0
),
m_uRoiX
(
0
),
m_uRoiY
(
0
),
m_uRoiY
(
0
),
m_uRoiW
(
0
),
m_uRoiW
(
0
),
...
@@ -188,6 +192,17 @@ XenethCamera::~XenethCamera()
...
@@ -188,6 +192,17 @@ XenethCamera::~XenethCamera()
LOG
((
"XenethCamera::~XenethCamera(%p) m_bInitialized=%d
\n
"
,
this
,
m_bInitialized
));
LOG
((
"XenethCamera::~XenethCamera(%p) m_bInitialized=%d
\n
"
,
this
,
m_bInitialized
));
if
(
m_bInitialized
)
if
(
m_bInitialized
)
Shutdown
();
Shutdown
();
m_hMutex
.
lock
();
if
(
m_pCameraThread
)
{
std
::
thread
*
pThread
(
m_pCameraThread
);
m_pCameraThread
=
nullptr
;
m_hMutex
.
unlock
();
pThread
->
join
();
delete
pThread
;
}
else
m_hMutex
.
unlock
();
g_hLogMutex
.
lock
();
g_hLogMutex
.
lock
();
m_apInstances
.
remove
(
this
);
m_apInstances
.
remove
(
this
);
g_hLogMutex
.
unlock
();
g_hLogMutex
.
unlock
();
...
@@ -308,7 +323,7 @@ int XenethCamera::Initialize()
...
@@ -308,7 +323,7 @@ int XenethCamera::Initialize()
AddAllowedValue
(
p
.
m_szName
.
c_str
(),
szRange
.
substr
(
0
,
iIndex
).
c_str
(),
lValue
++
);
AddAllowedValue
(
p
.
m_szName
.
c_str
(),
szRange
.
substr
(
0
,
iIndex
).
c_str
(),
lValue
++
);
szRange
.
erase
(
0
,
iIndex
+
1
);
szRange
.
erase
(
0
,
iIndex
+
1
);
}
}
SetPropertyLimits
(
p
.
m_szName
.
c_str
(),
0
,
lValue
-
1
);
SetPropertyLimits
(
p
.
m_szName
.
c_str
(),
0
,
static_cast
<
double
>
(
lValue
)
-
1
.
);
}
}
else
if
((
p
.
m_iType
&
XType_Base_Mask
)
==
XType_Base_Number
&&
!
p
.
m_szRange
.
empty
()
&&
else
if
((
p
.
m_iType
&
XType_Base_Mask
)
==
XType_Base_Number
&&
!
p
.
m_szRange
.
empty
()
&&
(
iIndex
=
p
.
m_szRange
.
find
(
'>'
))
!=
std
::
string
::
npos
)
(
iIndex
=
p
.
m_szRange
.
find
(
'>'
))
!=
std
::
string
::
npos
)
...
@@ -333,7 +348,8 @@ int XenethCamera::Initialize()
...
@@ -333,7 +348,8 @@ int XenethCamera::Initialize()
do
do
{
{
std
::
string
szName
(
p
.
m_szName
);
std
::
string
szName
(
p
.
m_szName
);
std
::
transform
(
szName
.
begin
(),
szName
.
end
(),
szName
.
begin
(),
std
::
tolower
);
// see <https://en.cppreference.com/w/cpp/string/byte/tolower>, why this is needed:
std
::
transform
(
szName
.
begin
(),
szName
.
end
(),
szName
.
begin
(),
[](
char
c
){
return
static_cast
<
char
>
(
std
::
tolower
(
static_cast
<
unsigned
char
>
(
c
)));});
for
(
iIndex
=
0
;
iIndex
<
szName
.
size
();
++
iIndex
)
for
(
iIndex
=
0
;
iIndex
<
szName
.
size
();
++
iIndex
)
if
(
!
std
::
isalnum
(
szName
[
iIndex
]))
if
(
!
std
::
isalnum
(
szName
[
iIndex
]))
szName
.
erase
(
iIndex
--
,
1
);
szName
.
erase
(
iIndex
--
,
1
);
...
@@ -352,8 +368,6 @@ int XenethCamera::Initialize()
...
@@ -352,8 +368,6 @@ int XenethCamera::Initialize()
m_aProperties
.
push_back
(
p
);
m_aProperties
.
push_back
(
p
);
}
}
m_bInitialized
=
true
;
m_bInitializing
=
false
;
CreateStringProperty
(
MM
::
g_Keyword_Name
,
"Xeneth Camera"
,
true
);
// Name
CreateStringProperty
(
MM
::
g_Keyword_Name
,
"Xeneth Camera"
,
true
);
// Name
CreateStringProperty
(
MM
::
g_Keyword_Description
,
"Xeneth/Xenics Camera"
,
true
);
// Description
CreateStringProperty
(
MM
::
g_Keyword_Description
,
"Xeneth/Xenics Camera"
,
true
);
// Description
CreateStringProperty
(
MM
::
g_Keyword_CameraName
,
szCameraSerial
.
c_str
(),
true
);
// CameraName
CreateStringProperty
(
MM
::
g_Keyword_CameraName
,
szCameraSerial
.
c_str
(),
true
);
// CameraName
...
@@ -386,12 +400,34 @@ int XenethCamera::Initialize()
...
@@ -386,12 +400,34 @@ int XenethCamera::Initialize()
}
}
LOG
((
"XenethCamera::Initialize(%p) m_lExposurePropertyIndex=%d
\n
"
,
this
,
static_cast
<
int
>
(
m_lExposurePropertyIndex
)));
LOG
((
"XenethCamera::Initialize(%p) m_lExposurePropertyIndex=%d
\n
"
,
this
,
static_cast
<
int
>
(
m_lExposurePropertyIndex
)));
ClearROI
();
ClearROI
();
// start background thread for camera readout and wait for successful run (at least one cycle)
m_hMutex
.
lock
();
m_bDoCameraThread
=
false
;
m_pCameraThread
=
new
std
::
thread
(
&
CameraThreadFunc
,
this
);
m_hMutex
.
unlock
();
while
(
!
m_bDoCameraThread
)
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
50
));
m_bInitialized
=
true
;
m_bInitializing
=
false
;
return
DEVICE_OK
;
return
DEVICE_OK
;
}
}
int
XenethCamera
::
Shutdown
()
int
XenethCamera
::
Shutdown
()
{
{
LOG
((
"XenethCamera::Shutdown(%p) m_bInitialized=%d
\n
"
,
this
,
m_bInitialized
));
LOG
((
"XenethCamera::Shutdown(%p) m_bInitialized=%d
\n
"
,
this
,
m_bInitialized
));
m_hMutex
.
lock
();
if
(
m_pCameraThread
)
{
std
::
thread
*
pThread
(
m_pCameraThread
);
m_pCameraThread
=
nullptr
;
m_hMutex
.
unlock
();
pThread
->
join
();
delete
pThread
;
}
else
m_hMutex
.
unlock
();
if
(
m_bInitialized
)
if
(
m_bInitialized
)
{
{
if
(
XC_IsCapturing
(
m_hCamera
))
if
(
XC_IsCapturing
(
m_hCamera
))
...
@@ -473,6 +509,9 @@ void XenethCamera::SetExposure(double exposure)
...
@@ -473,6 +509,9 @@ void XenethCamera::SetExposure(double exposure)
XC_SetPropertyValue
(
m_hCamera
,
p
->
m_szName
.
c_str
(),
p
->
m_szValue
.
c_str
(),
nullptr
);
XC_SetPropertyValue
(
m_hCamera
,
p
->
m_szName
.
c_str
(),
p
->
m_szValue
.
c_str
(),
nullptr
);
break
;
break
;
}
}
m_hMutex
.
lock
();
m_byCameraTrigger
=
2
;
m_hMutex
.
unlock
();
}
}
}
}
...
@@ -508,7 +547,7 @@ double XenethCamera::GetExposure() const
...
@@ -508,7 +547,7 @@ double XenethCamera::GetExposure() const
{
{
std
::
string
szValue
;
std
::
string
szValue
;
szValue
.
resize
(
65536
);
szValue
.
resize
(
65536
);
if
(
XC_GetPropertyValue
(
m_hCamera
,
p
->
m_szName
.
c_str
(),
&
szValue
[
0
],
szValue
.
size
())
==
I_OK
)
if
(
XC_GetPropertyValue
(
m_hCamera
,
p
->
m_szName
.
c_str
(),
&
szValue
[
0
],
static_cast
<
int
>
(
szValue
.
size
())
)
==
I_OK
)
{
{
szValue
[
szValue
.
size
()
-
1
]
=
'\0'
;
szValue
[
szValue
.
size
()
-
1
]
=
'\0'
;
szValue
.
resize
(
strlen
(
szValue
.
c_str
()));
szValue
.
resize
(
strlen
(
szValue
.
c_str
()));
...
@@ -607,10 +646,11 @@ void XenethCamera::UpdateROI()
...
@@ -607,10 +646,11 @@ void XenethCamera::UpdateROI()
pSrc
.
u8
=
m_abyImage
.
data
();
pSrc
.
u8
=
m_abyImage
.
data
();
pDst
.
u8
=
m_abyROI
.
data
();
pDst
.
u8
=
m_abyROI
.
data
();
unsigned
uRoiRight
(
m_uRoiX
+
m_uRoiW
);
unsigned
uRoiBottom
(
m_uRoiX
+
m_uRoiW
);
for
(
iSrc
=
iDst
=
iX
=
iY
=
0
;
iY
<
m_uRoiH
;
++
iSrc
)
for
(
iSrc
=
iDst
=
iX
=
iY
=
0
;
iY
<
m_uRoiH
;
++
iSrc
)
{
{
if
(
iX
>=
m_uRoiX
&&
iX
<
(
m_uRoiX
+
m_uRoiW
)
&&
if
(
iX
>=
m_uRoiX
&&
iX
<
uRoiRight
&&
iY
>=
m_uRoiY
&&
iY
<
uRoiBottom
)
iY
>=
m_uRoiY
&&
iY
<
(
m_uRoiY
+
m_uRoiH
))
{
{
switch
(
iFrameType
)
switch
(
iFrameType
)
{
{
...
@@ -694,26 +734,58 @@ unsigned XenethCamera::GetImageBytesPerPixel() const
...
@@ -694,26 +734,58 @@ unsigned XenethCamera::GetImageBytesPerPixel() const
int
XenethCamera
::
SnapImage
()
int
XenethCamera
::
SnapImage
()
{
{
static
int
g_iSnapCount
(
0
);
if
(
!
m_bInitialized
||
!
m_pCameraThread
)
if
(
g_iSnapCount
<
1000
)
return
DEVICE_ERR
;
LOG
((
"XenethCamera::SnapImage(%p) trigger
\n
"
,
this
));
m_hMutex
.
lock
();
m_abyImage
.
resize
(
XC_GetFrameSize
(
m_hCamera
),
0
);
if
(
!
XC_IsCapturing
(
m_hCamera
))
if
(
!
XC_IsCapturing
(
m_hCamera
))
{
{
int
iResult
(
ConvertXenethResult
(
XC_StartCapture
(
m_hCamera
)));
int
iResult
(
ConvertXenethResult
(
XC_StartCapture
(
m_hCamera
)));
LOG
((
"XenethCamera::SnapImage(%p) started camera, iResult=%d
\n
"
,
this
,
iResult
));
LOG
((
"XenethCamera::SnapImage(%p) started camera, iResult=%d
\n
"
,
this
,
iResult
));
if
(
iResult
!=
DEVICE_OK
)
{
m_hMutex
.
unlock
();
return
iResult
;
}
m_abyImage
.
resize
(
XC_GetFrameSize
(
m_hCamera
),
0
);
}
}
LOG
((
"XenethCamera::SnapImage(%p) frame count=%u
\n
"
,
this
,
XC_GetFrameCount
(
m_hCamera
)));
m_bDoCameraThread
=
false
;
int
iResult
(
ConvertXenethResult
(
XC_GetFrame
(
m_hCamera
,
FT_NATIVE
,
XGF_Blocking
,
m_hMutex
.
unlock
();
static_cast
<
void
*>
(
m_abyImage
.
data
()),
static_cast
<
int
>
(
m_abyImage
.
size
()))));
while
(
m_bInitialized
&&
m_pCameraThread
&&
!
m_bDoCameraThread
&&
m_byCameraTrigger
)
if
(
g_iSnapCount
<
1000
||
iResult
!=
DEVICE_OK
)
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
20
));
UpdateROI
();
return
m_iLastCameraResult
;
}
void
XenethCamera
::
CameraThread
()
{
LOG
((
"XenethCamera::CameraThread(%p) start
\n
"
,
this
));
while
(
m_pCameraThread
)
{
{
++
g_iSnapCount
;
m_hMutex
.
lock
();
LOG
((
"XenethCamera::SnapImage(%p) size=%u iResult=%d
\n
"
,
this
,
m_abyImage
.
size
(),
iResult
));
if
(
m_bInitialized
&&
XC_IsCapturing
(
m_hCamera
))
{
m_abyImageTmp
.
resize
(
XC_GetFrameSize
(
m_hCamera
),
0
);
ErrCode
dwErr
(
XC_GetFrame
(
m_hCamera
,
FT_NATIVE
,
0
,
static_cast
<
void
*>
(
m_abyImageTmp
.
data
()),
static_cast
<
int
>
(
m_abyImageTmp
.
size
())));
m_iLastCameraResult
=
ConvertXenethResult
(
dwErr
);
if
(
dwErr
==
I_OK
)
{
m_abyImage
.
swap
(
m_abyImageTmp
);
if
(
m_byCameraTrigger
>
0
)
--
m_byCameraTrigger
;
}
else
{
LOG
((
"XenethCamera::CameraThread(%p) camera error %u, iResult=%d
\n
"
,
this
,
dwErr
,
m_iLastCameraResult
));
if
(
m_byCameraTrigger
>
0
)
m_byCameraTrigger
=
1
;
}
}
m_bDoCameraThread
=
true
;
m_hMutex
.
unlock
();
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
20
));
}
}
if
(
iResult
==
DEVICE_OK
)
m_bDoCameraThread
=
false
;
UpdateROI
();
LOG
((
"XenethCamera::CameraThread(%p) end
\n
"
,
this
));
return
iResult
;
}
}
int
XenethCamera
::
StartSequenceAcquisition
(
long
numImages
,
double
interval_ms
,
bool
stopOnOverflow
)
int
XenethCamera
::
StartSequenceAcquisition
(
long
numImages
,
double
interval_ms
,
bool
stopOnOverflow
)
...
@@ -722,6 +794,19 @@ int XenethCamera::StartSequenceAcquisition(long numImages, double interval_ms, b
...
@@ -722,6 +794,19 @@ int XenethCamera::StartSequenceAcquisition(long numImages, double interval_ms, b
LOG
((
"XenethCamera::StartSequenceAcquisition(%p) started camera, iResult=%d
\n
"
,
this
,
iResult
));
LOG
((
"XenethCamera::StartSequenceAcquisition(%p) started camera, iResult=%d
\n
"
,
this
,
iResult
));
if
(
iResult
!=
DEVICE_OK
)
if
(
iResult
!=
DEVICE_OK
)
return
iResult
;
return
iResult
;
m_hMutex
.
lock
();
if
(
XC_IsCapturing
(
m_hCamera
))
// restart camera to handle longer exposure times
{
XC_StopCapture
(
m_hCamera
);
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
50
));
XC_StartCapture
(
m_hCamera
);
}
m_abyImage
.
resize
(
XC_GetFrameSize
(
m_hCamera
),
0
);
if
(
!
m_byCameraTrigger
)
m_byCameraTrigger
=
1
;
// wait for next image
m_hMutex
.
unlock
();
return
CCameraBase
::
StartSequenceAcquisition
(
numImages
,
interval_ms
,
stopOnOverflow
);
return
CCameraBase
::
StartSequenceAcquisition
(
numImages
,
interval_ms
,
stopOnOverflow
);
}
}
...
...
XenethCamera.h
View file @
29f6cb28
...
@@ -78,31 +78,37 @@ private:
...
@@ -78,31 +78,37 @@ private:
XenethProperty
&
operator
=
(
const
XenethProperty
&
)
=
default
;
XenethProperty
&
operator
=
(
const
XenethProperty
&
)
=
default
;
XenethProperty
&
operator
=
(
XenethProperty
&&
)
=
default
;
XenethProperty
&
operator
=
(
XenethProperty
&&
)
=
default
;
XPropType
m_iType
;
XPropType
m_iType
;
/// type of property (data type and more)
std
::
string
m_szName
;
std
::
string
m_szName
;
/// name of property
std
::
string
m_szCategory
;
std
::
string
m_szCategory
;
/// property category
std
::
string
m_szUnit
;
std
::
string
m_szUnit
;
/// unit of property
std
::
string
m_szRange
;
std
::
string
m_szRange
;
/// data range of property
std
::
string
m_szValue
;
std
::
string
m_szValue
;
/// value of property
};
};
mutable
bool
m_bInitialized
;
mutable
bool
m_bInitialized
;
/// flag, if driver is initialized
mutable
bool
m_bInitializing
;
mutable
bool
m_bInitializing
;
/// flag, while initializing
unsigned
char
m_byPixelSize
;
std
::
recursive_mutex
m_hMutex
;
/// mutex (thread synchronisation)
std
::
string
m_szCameraPath
;
unsigned
char
m_byPixelSize
;
/// byte size of one pixel
std
::
string
m_szCalibrationFile
;
std
::
string
m_szCameraPath
;
/// Xeneth path to camera
XCHANDLE
m_hCamera
;
std
::
string
m_szCalibrationFile
;
/// file path to calibration file
std
::
vector
<
XenethProperty
>
m_aProperties
;
XCHANDLE
m_hCamera
;
/// camera handle
long
m_lExposurePropertyIndex
;
std
::
vector
<
XenethProperty
>
m_aProperties
;
/// list of camera properties
long
m_lExposurePropertyIndex
;
/// index of exposure property
bool
m_bDoCameraThread
;
/// background thread info
std
::
thread
*
m_pCameraThread
;
/// camera background thread handle
unsigned
char
m_byCameraTrigger
;
/// trigger count for camera
int
m_iLastCameraResult
;
/// last camera result
static
std
::
list
<
XenethCamera
*>
m_apInstances
;
/// list of active instances for exit
static
std
::
list
<
XenethCamera
*>
m_apInstances
;
/// list of active instances for exit
mutable
unsigned
m_uRoiX
;
mutable
unsigned
m_uRoiX
;
/// horizontal position of ROI
mutable
unsigned
m_uRoiY
;
mutable
unsigned
m_uRoiY
;
/// vertical position of ROI
mutable
unsigned
m_uRoiW
;
mutable
unsigned
m_uRoiW
;
/// width of ROI
mutable
unsigned
m_uRoiH
;
mutable
unsigned
m_uRoiH
;
/// height of ROI
std
::
vector
<
unsigned
char
>
m_abyImage
;
std
::
vector
<
unsigned
char
>
m_abyImage
;
/// last valid camera image
std
::
vector
<
unsigned
char
>
m_abyROI
;
std
::
vector
<
unsigned
char
>
m_abyImageTmp
;
/// temporary camera image
std
::
vector
<
unsigned
char
>
m_abyROI
;
/// ROI of last valid camera image
/// <summary>
/// <summary>
/// convienence function to create a MM property with local action function
/// convienence function to create a MM property with local action function
...
@@ -165,6 +171,18 @@ private:
...
@@ -165,6 +171,18 @@ private:
/// <returns>success or error code</returns>
/// <returns>success or error code</returns>
int
OnCameraProperty
(
MM
::
PropertyBase
*
pProp
,
MM
::
ActionType
eAct
);
int
OnCameraProperty
(
MM
::
PropertyBase
*
pProp
,
MM
::
ActionType
eAct
);
/// <summary>
/// implements the camera background thread
/// </summary>
void
CameraThread
();
/// <summary>
/// called for camera background thread
/// </summary>
/// <param name="pInstance">pointer to this instance</param>
static
void
CameraThreadFunc
(
void
*
pInstance
)
{
reinterpret_cast
<
XenethCamera
*>
(
pInstance
)
->
CameraThread
();
}
/// <summary>
/// <summary>
/// update ROI image from camera image
/// update ROI image from camera image
/// </summary>
/// </summary>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment