dev
This commit is contained in:
parent
f2aa761ad9
commit
e93d25c33e
|
|
@ -226,114 +226,193 @@ mv_lib.MV_VS_SetStringValue.restype = c_int
|
|||
|
||||
|
||||
def MV_VS_GetFrame(handle, name=""):
|
||||
"""
|
||||
Get a frame from the camera with enhanced error handling to prevent access violations.
|
||||
|
||||
Args:
|
||||
handle: Camera handle
|
||||
name: Optional name for debugging
|
||||
|
||||
Returns:
|
||||
dict: Dictionary containing frame data and results, or None if an error occurred
|
||||
"""
|
||||
# Create a logger for this function
|
||||
import logging
|
||||
logger = logging.getLogger("MV_VS_GetFrame")
|
||||
|
||||
try:
|
||||
stFrameData = MV_VS_DATA()
|
||||
|
||||
stFrameData = MV_VS_DATA()
|
||||
|
||||
nRet = mv_lib.MV_VS_GetResultData(handle, byref(stFrameData), 500)
|
||||
if nRet == MV_VS_OK:
|
||||
# Print frame information
|
||||
# print(f"Frame Width: [{stFrameData.nImageWidth}], Height: [{stFrameData.nImageHeight}], ImageLen: [{stFrameData.nImageLen}]")
|
||||
# Get result data with timeout
|
||||
nRet = mv_lib.MV_VS_GetResultData(handle, byref(stFrameData), 500)
|
||||
if nRet != MV_VS_OK:
|
||||
error_code = nRet & 0xFFFFFFFF
|
||||
logger.error(f"MV_VS_GetResultData failed! Error code: 0x{error_code:x}")
|
||||
|
||||
# Special handling for 0x80030100 (MV_VS_E_GC_GENERIC)
|
||||
if error_code == 0x80030100:
|
||||
logger.warning("Detected MV_VS_E_GC_GENERIC error (0x80030100) during frame acquisition")
|
||||
logger.info("This is a non-critical error, will return None")
|
||||
|
||||
return None
|
||||
|
||||
# Validate frame data
|
||||
if stFrameData.pImage is None:
|
||||
logger.error("Frame data contains null image pointer")
|
||||
return None
|
||||
|
||||
if stFrameData.nImageLen <= 0:
|
||||
logger.error(f"Invalid image length: {stFrameData.nImageLen}")
|
||||
return None
|
||||
|
||||
# Process chunk data
|
||||
currentDataTag = 0
|
||||
chResultInfo = {}
|
||||
while stFrameData.nChunkDataLen > currentDataTag:
|
||||
chunkLength = ctypes.c_uint32()
|
||||
chunkID = ctypes.c_uint32()
|
||||
|
||||
# Calculate source addresses for chunkLength and chunkID
|
||||
source_address_length = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 4 - currentDataTag
|
||||
source_address_id = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - currentDataTag
|
||||
|
||||
# Copy data from source to chunkLength and chunkID
|
||||
ctypes.memmove(ctypes.byref(chunkLength), source_address_length, 4)
|
||||
ctypes.memmove(ctypes.byref(chunkID), source_address_id, 4)
|
||||
|
||||
# Convert network byte order to host byte order
|
||||
chunkLength.value = socket.ntohl(chunkLength.value)
|
||||
chunkID.value = socket.ntohl(chunkID.value)
|
||||
|
||||
# Print the values
|
||||
#print(f"chunkLength [{chunkLength.value}], chunkID: [{chunkID.value}]")
|
||||
|
||||
if chunkLength.value <= 0 or chunkLength.value > stFrameData.nChunkDataLen - 8 - currentDataTag:
|
||||
break
|
||||
|
||||
if chunkID.value == CHUNK_RESULT_PORT: # Result data in JSON format
|
||||
chRawInfo = ctypes.cast(stFrameData.pChunkData, ctypes.POINTER(ctypes.c_char))
|
||||
chRawInfo = ctypes.cast(ctypes.addressof(
|
||||
chRawInfo.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag,
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
|
||||
chResultInfo = ctypes.string_at(chRawInfo, chunkLength.value)
|
||||
chResultInfo = json.loads(chResultInfo.decode())
|
||||
|
||||
# if chResultInfo:
|
||||
# print(f"chResultInfo OK")
|
||||
|
||||
elif chunkID.value == CHUNK_MASK_IMAGE_PORT: # Mask image data
|
||||
maskModID = ctypes.c_uint32()
|
||||
maskModFormat = ctypes.c_uint32()
|
||||
maskModWidth = ctypes.c_uint32()
|
||||
maskModHeight = ctypes.c_uint32()
|
||||
|
||||
# Calculate source addresses
|
||||
source_address_id = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag
|
||||
source_address_format = source_address_id + 4
|
||||
source_address_width = source_address_id + 8
|
||||
source_address_height = source_address_id + 12
|
||||
|
||||
# Copy data from source addresses to corresponding variables
|
||||
ctypes.memmove(ctypes.byref(maskModID), source_address_id, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModFormat), source_address_format, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModWidth), source_address_width, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModHeight), source_address_height, 4)
|
||||
|
||||
# print(f"Mask ModID[{maskModID.value}], ModFormat[{maskModFormat.value}], ModWidth[{maskModWidth.value}], ModHeight[{maskModHeight.value}], ")
|
||||
|
||||
try:
|
||||
chMaskModImageData = ctypes.cast(ctypes.create_string_buffer(chunkLength.value - 16 + 1),
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
if chMaskModImageData:
|
||||
ctypes.memset(chMaskModImageData, 0, chunkLength.value - 16 + 1)
|
||||
chImageData = ctypes.cast(ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag + 16,
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
ctypes.memmove(chMaskModImageData, chImageData, chunkLength.value - 16)
|
||||
# print(f"Mask data length [{chunkLength.value - 16}]")
|
||||
|
||||
except (MemoryError, TypeError) as e:
|
||||
print(f"Error allocating or copying memory: {e}")
|
||||
|
||||
currentDataTag = currentDataTag + 8 + chunkLength.value
|
||||
# end process chunk data
|
||||
|
||||
m_stJpgParam = MV_VS_JPG_PARAM()
|
||||
m_stJpgParam.pBufInput = ctypes.cast(stFrameData.pImage,ctypes.POINTER(ctypes.c_ubyte))
|
||||
m_stJpgParam.nBufInputLen = stFrameData.nImageLen
|
||||
jpegContents = ctypes.string_at(m_stJpgParam.pBufInput, m_stJpgParam.nBufInputLen)
|
||||
|
||||
# with open(f"tmp/test_{name}.jpg", "wb") as f:
|
||||
# f.write(jpegContents)
|
||||
jpg_as_np = np.frombuffer(jpegContents, dtype=np.uint8)
|
||||
# Convert the NumPy array to an OpenCV image.
|
||||
img = cv2.imdecode(jpg_as_np, flags=1)
|
||||
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
||||
# Release frame buffer
|
||||
nRet = mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
|
||||
if nRet != MV_VS_OK:
|
||||
print(f"Release frame buffer fail! nRet [0x{nRet:x}]")
|
||||
|
||||
# Check if chunk data is valid
|
||||
if stFrameData.pChunkData is None:
|
||||
logger.warning("Chunk data pointer is null, skipping chunk processing")
|
||||
elif stFrameData.nChunkDataLen <= 0:
|
||||
logger.warning(f"Invalid chunk data length: {stFrameData.nChunkDataLen}")
|
||||
else:
|
||||
# print(f"Release frame buffer OK")
|
||||
pass
|
||||
# Process chunk data safely
|
||||
try:
|
||||
while stFrameData.nChunkDataLen > currentDataTag:
|
||||
chunkLength = ctypes.c_uint32()
|
||||
chunkID = ctypes.c_uint32()
|
||||
|
||||
# Calculate source addresses for chunkLength and chunkID
|
||||
try:
|
||||
source_address_length = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 4 - currentDataTag
|
||||
source_address_id = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - currentDataTag
|
||||
|
||||
# Copy data from source to chunkLength and chunkID
|
||||
ctypes.memmove(ctypes.byref(chunkLength), source_address_length, 4)
|
||||
ctypes.memmove(ctypes.byref(chunkID), source_address_id, 4)
|
||||
|
||||
# Convert network byte order to host byte order
|
||||
chunkLength.value = socket.ntohl(chunkLength.value)
|
||||
chunkID.value = socket.ntohl(chunkID.value)
|
||||
except (AttributeError, TypeError) as e:
|
||||
logger.error(f"Error accessing chunk data memory: {e}")
|
||||
break
|
||||
|
||||
# Validate chunk length
|
||||
if chunkLength.value <= 0 or chunkLength.value > stFrameData.nChunkDataLen - 8 - currentDataTag:
|
||||
logger.warning(f"Invalid chunk length: {chunkLength.value}, breaking chunk processing")
|
||||
break
|
||||
|
||||
# Process different chunk types
|
||||
try:
|
||||
if chunkID.value == CHUNK_RESULT_PORT: # Result data in JSON format
|
||||
chRawInfo = ctypes.cast(stFrameData.pChunkData, ctypes.POINTER(ctypes.c_char))
|
||||
chRawInfo = ctypes.cast(ctypes.addressof(
|
||||
chRawInfo.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag,
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
|
||||
chResultInfo_bytes = ctypes.string_at(chRawInfo, chunkLength.value)
|
||||
try:
|
||||
chResultInfo = json.loads(chResultInfo_bytes.decode())
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Error decoding JSON result data: {e}")
|
||||
chResultInfo = {}
|
||||
|
||||
elif chunkID.value == CHUNK_MASK_IMAGE_PORT: # Mask image data
|
||||
maskModID = ctypes.c_uint32()
|
||||
maskModFormat = ctypes.c_uint32()
|
||||
maskModWidth = ctypes.c_uint32()
|
||||
maskModHeight = ctypes.c_uint32()
|
||||
|
||||
# Calculate source addresses
|
||||
source_address_id = ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag
|
||||
source_address_format = source_address_id + 4
|
||||
source_address_width = source_address_id + 8
|
||||
source_address_height = source_address_id + 12
|
||||
|
||||
# Copy data from source addresses to corresponding variables
|
||||
ctypes.memmove(ctypes.byref(maskModID), source_address_id, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModFormat), source_address_format, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModWidth), source_address_width, 4)
|
||||
ctypes.memmove(ctypes.byref(maskModHeight), source_address_height, 4)
|
||||
|
||||
try:
|
||||
chMaskModImageData = ctypes.cast(ctypes.create_string_buffer(chunkLength.value - 16 + 1),
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
if chMaskModImageData:
|
||||
ctypes.memset(chMaskModImageData, 0, chunkLength.value - 16 + 1)
|
||||
chImageData = ctypes.cast(ctypes.addressof(
|
||||
stFrameData.pChunkData.contents) + stFrameData.nChunkDataLen - 8 - chunkLength.value - currentDataTag + 16,
|
||||
ctypes.POINTER(ctypes.c_char))
|
||||
ctypes.memmove(chMaskModImageData, chImageData, chunkLength.value - 16)
|
||||
except (MemoryError, TypeError, AttributeError) as e:
|
||||
logger.error(f"Error allocating or copying memory for mask data: {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing chunk ID {chunkID.value}: {e}")
|
||||
# Continue with next chunk
|
||||
|
||||
# Move to next chunk
|
||||
currentDataTag = currentDataTag + 8 + chunkLength.value
|
||||
except Exception as e:
|
||||
logger.error(f"Error during chunk data processing: {e}")
|
||||
# Continue with image processing despite chunk errors
|
||||
|
||||
# Process image data
|
||||
try:
|
||||
m_stJpgParam = MV_VS_JPG_PARAM()
|
||||
m_stJpgParam.pBufInput = ctypes.cast(stFrameData.pImage, ctypes.POINTER(ctypes.c_ubyte))
|
||||
m_stJpgParam.nBufInputLen = stFrameData.nImageLen
|
||||
|
||||
# Safely get JPEG contents
|
||||
try:
|
||||
jpegContents = ctypes.string_at(m_stJpgParam.pBufInput, m_stJpgParam.nBufInputLen)
|
||||
except (TypeError, ValueError) as e:
|
||||
logger.error(f"Error accessing JPEG data: {e}")
|
||||
# Release frame buffer before returning
|
||||
mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
return None
|
||||
|
||||
# Convert to numpy array and then to OpenCV image
|
||||
try:
|
||||
jpg_as_np = np.frombuffer(jpegContents, dtype=np.uint8)
|
||||
img = cv2.imdecode(jpg_as_np, flags=1)
|
||||
|
||||
if img is None:
|
||||
logger.error("Failed to decode JPEG data")
|
||||
# Release frame buffer before returning
|
||||
mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
return None
|
||||
|
||||
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
||||
except Exception as e:
|
||||
logger.error(f"Error converting JPEG to image: {e}")
|
||||
# Release frame buffer before returning
|
||||
mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing image data: {e}")
|
||||
# Release frame buffer before returning
|
||||
mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
return None
|
||||
|
||||
# Release frame buffer
|
||||
try:
|
||||
nRet = mv_lib.MV_VS_ReleaseResultData(handle, ctypes.byref(stFrameData))
|
||||
if nRet != MV_VS_OK:
|
||||
error_code = nRet & 0xFFFFFFFF
|
||||
logger.warning(f"Release frame buffer failed! Error code: 0x{error_code:x}")
|
||||
except Exception as e:
|
||||
logger.error(f"Exception during frame buffer release: {e}")
|
||||
|
||||
# Return the processed frame and results
|
||||
return {"frame": img, "res": chResultInfo}
|
||||
else:
|
||||
print(f"MV_VS_GetResultData fail! nRet [0x{nRet&0xFFFFFFFF:x}]")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Unhandled exception in MV_VS_GetFrame: {e}")
|
||||
import traceback
|
||||
logger.error(f"Exception traceback: {traceback.format_exc()}")
|
||||
return None
|
||||
|
||||
def print_device_info(device_info_list):
|
||||
|
|
|
|||
|
|
@ -241,23 +241,47 @@ class HikrobotSmartCamera(Component):
|
|||
|
||||
def refresh_module_list(self):
|
||||
"""
|
||||
Refresh the module list after switching schemes.
|
||||
Refresh the module list after switching schemes with enhanced error handling.
|
||||
|
||||
Returns:
|
||||
bool: True if successful, False otherwise
|
||||
"""
|
||||
if not self.connected:
|
||||
self.log.error("Cannot refresh module list: Camera not connected")
|
||||
return False
|
||||
|
||||
# Get the first camera handle
|
||||
# Check connection status with retry mechanism
|
||||
retry_count = 0
|
||||
max_retries = 3
|
||||
|
||||
while retry_count < max_retries:
|
||||
if not self.connected:
|
||||
self.log.warning(f"Camera not connected during module list refresh (attempt {retry_count+1}/{max_retries})")
|
||||
if retry_count == max_retries - 1:
|
||||
self.log.error("Cannot refresh module list: Camera not connected after retries")
|
||||
return False
|
||||
|
||||
# Wait and retry
|
||||
self.log.info("Waiting 1 second before retrying connection check")
|
||||
time.sleep(1)
|
||||
retry_count += 1
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
# Get the first camera handle with validation
|
||||
if len(self.cam_list) == 0:
|
||||
self.log.error("Cannot refresh module list: No camera handles available")
|
||||
return False
|
||||
|
||||
handle = self.cam_list[0]["handle"]
|
||||
# Validate handle before using it
|
||||
handle = self.cam_list[0].get("handle")
|
||||
if handle is None:
|
||||
self.log.error("Cannot refresh module list: Camera handle is None")
|
||||
return False
|
||||
|
||||
# Add a delay before refreshing to allow camera to stabilize
|
||||
time.sleep(0.5)
|
||||
|
||||
try:
|
||||
self.log.info("Attempting to refresh module list")
|
||||
|
||||
# Command to refresh module list
|
||||
nRet = mv_lib.MV_VS_SetCommandValue(handle, b"CommandRefreshModuleList")
|
||||
if nRet != MV_VS_OK:
|
||||
|
|
@ -271,6 +295,13 @@ class HikrobotSmartCamera(Component):
|
|||
# We'll return True here to avoid treating this as a fatal error
|
||||
return True
|
||||
|
||||
# For other error codes, check if we should retry
|
||||
if retry_count < max_retries - 1:
|
||||
retry_count += 1
|
||||
self.log.warning(f"Retrying module list refresh after error (attempt {retry_count}/{max_retries})")
|
||||
time.sleep(1) # Wait before retrying
|
||||
return self.refresh_module_list() # Recursive retry
|
||||
|
||||
return False
|
||||
|
||||
self.log.info("Module list refreshed successfully")
|
||||
|
|
@ -280,7 +311,10 @@ class HikrobotSmartCamera(Component):
|
|||
# Log the full exception traceback for debugging
|
||||
import traceback
|
||||
self.log.error(f"Exception traceback: {traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
# Return True for non-critical exceptions to avoid blocking the workflow
|
||||
self.log.info("Treating exception as non-critical, continuing operation")
|
||||
return True
|
||||
|
||||
def switch_scheme(self, solution_name, retry_count=0, max_retries=2):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user