You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
487 lines
24 KiB
487 lines
24 KiB
#!/usr/bin/python
|
|
# -*- coding:utf-8 -*-
|
|
# -*-mode:python ; tab-width:4 -*- ex:set tabstop=4 shiftwidth=4 expandtab: -*-
|
|
|
|
|
|
import numpy
|
|
|
|
from .. import gxipy
|
|
from .gxwrapper import *
|
|
from .dxwrapper import *
|
|
from .gxidef import *
|
|
from .ImageFormatConvert import *
|
|
from .ImageProcessConfig import *
|
|
from .Exception import *
|
|
import types
|
|
|
|
class ImageProcess:
|
|
|
|
def __init__(self):
|
|
self.image_convert_handle = None
|
|
|
|
def __new__(cls, *args, **kw):
|
|
return object.__new__(cls, *args)
|
|
|
|
def __del__(self):
|
|
if self.image_convert_handle is not None:
|
|
status = dx_image_format_convert_destroy(self.image_convert_handle)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_destroy failure, Error code:%s" % hex(status).__str__())
|
|
self.image_convert_handle = None
|
|
|
|
def image_improvement(self, image, output_address, image_process_config):
|
|
"""
|
|
:brief: Improve image quality of the raw_image
|
|
:param image: image is RawImage or GXImageInfo
|
|
|
|
:param output_address: output image
|
|
:param image_process_config: image process config
|
|
:param
|
|
:return: None
|
|
"""
|
|
if output_address is None:
|
|
raise ParameterTypeError("output_address param is null pointer.")
|
|
|
|
if not isinstance(image_process_config, ImageProcessConfig):
|
|
raise ParameterTypeError("image_process_config param must be ImageProcessConfig type.")
|
|
|
|
pixel_format = GxPixelFormatEntry.UNDEFINED
|
|
raw_image_width = 0
|
|
raw_image_height = 0
|
|
input_image_buffer = None
|
|
channel_order = DxRGBChannelOrder.ORDER_RGB
|
|
if isinstance(image, (RawImage, RGBImage)):
|
|
pixel_format = image.frame_data.pixel_format
|
|
raw_image_width = image.frame_data.width
|
|
raw_image_height = image.frame_data.height
|
|
input_image_buffer = image.frame_data.image_buf
|
|
elif isinstance(image, GxImageInfo):
|
|
pixel_format = image.image_pixel_format
|
|
raw_image_width = image.image_width
|
|
raw_image_height = image.image_height
|
|
input_image_buffer = image.image_buf
|
|
else:
|
|
raise ParameterTypeError("image param must be RawImage or GxImageInfo type.")
|
|
|
|
if input_image_buffer is None:
|
|
raise ParameterTypeError("input_image_buffer param is null pointer.")
|
|
|
|
if pixel_format == GxPixelFormatEntry.RGB8:
|
|
channel_order = DxRGBChannelOrder.ORDER_RGB
|
|
elif pixel_format == GxPixelFormatEntry.BGR8:
|
|
channel_order = DxRGBChannelOrder.ORDER_BGR
|
|
|
|
if pixel_format in (GxPixelFormatEntry.RGB8, GxPixelFormatEntry.BGR8):
|
|
if pixel_format == GxPixelFormatEntry.BGR8:
|
|
|
|
self.__check_handle()
|
|
status = dx_image_format_convert_set_output_pixel_format(self.image_convert_handle,
|
|
GxPixelFormatEntry.RGB8)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_set_output_pixel_format failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
status = dx_image_format_convert_set_valid_bits(self.image_convert_handle, DxValidBit.BIT0_7)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"image_format_convert_set_alpha_value failure, Error code:%s" % hex(status).__str__())
|
|
|
|
status, out_lenght = dx_image_format_convert_get_buffer_size_for_conversion(self.image_convert_handle,
|
|
GxPixelFormatEntry.RGB8,
|
|
image.frame_data.width,
|
|
image.frame_data.height)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_get_buffer_size_for_conversion failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
image_temp = (c_ubyte * out_lenght)()
|
|
output_image_temp = addressof(image_temp)
|
|
|
|
status, input_length = dx_image_format_convert_get_buffer_size_for_conversion(self.image_convert_handle,
|
|
image.frame_data.pixel_format,
|
|
image.frame_data.width,
|
|
image.frame_data.height)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_get_buffer_size_for_conversion failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
status = dx_image_format_convert(self.image_convert_handle, image.frame_data.image_buf, input_length,
|
|
output_image_temp,
|
|
out_lenght, image.frame_data.pixel_format,
|
|
image.frame_data.width, image.frame_data.height, False)
|
|
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("image_format_convert failure, Error code:%s" % hex(status).__str__())
|
|
|
|
input_image_buffer = output_image_temp
|
|
status = dx_image_improvement_ex(input_image_buffer, output_address,
|
|
raw_image_width, raw_image_height,
|
|
image_process_config.get_color_correction_param(),
|
|
image_process_config.get_contrast_lut().get_ctype_array(),
|
|
image_process_config.get_gamma_lut().get_ctype_array(),
|
|
channel_order)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("RGBImage.image_improvement: failed, error code:%s" % hex(status).__str__())
|
|
return
|
|
|
|
if Utility.is_gray(pixel_format):
|
|
ImageProcess.__mono_image_process(self, output_address, image, image_process_config)
|
|
else:
|
|
rgb_image_array_temp = (c_ubyte * image.frame_data.height * image.frame_data.width * 3)()
|
|
rgb_image_array_temp_address = addressof(rgb_image_array_temp)
|
|
ImageProcess.__raw_image_process(rgb_image_array_temp_address, image, image_process_config)
|
|
|
|
# convert to rgb
|
|
self.__check_handle()
|
|
status = dx_image_format_convert_set_output_pixel_format(self.image_convert_handle,
|
|
GxPixelFormatEntry.RGB8)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_set_output_pixel_format failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
status = dx_image_format_convert_set_valid_bits(self.image_convert_handle, DxValidBit.BIT0_7)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"image_format_convert_set_alpha_value failure, Error code:%s" % hex(status).__str__())
|
|
|
|
status, out_lenght = dx_image_format_convert_get_buffer_size_for_conversion(self.image_convert_handle,
|
|
GxPixelFormatEntry.BGR8,
|
|
image.frame_data.width,
|
|
image.frame_data.height)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_get_buffer_size_for_conversion failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
input_length = image.frame_data.width * image.frame_data.height * 3
|
|
status = dx_image_format_convert(self.image_convert_handle, rgb_image_array_temp_address, input_length,
|
|
output_address,
|
|
out_lenght, GxPixelFormatEntry.BGR8,
|
|
image.frame_data.width, image.frame_data.height, False)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("image_format_convert failure, Error code:%s" % hex(status).__str__())
|
|
|
|
|
|
def static_defect_correction(self, input_address, output_address, defect_correction, defect_pos_buffer_address,
|
|
defect_pos_buffer_size):
|
|
"""
|
|
:brief Image defect pixel correction
|
|
:param input_address: The input raw image buff address, buff size = width * height
|
|
:param output_address: The output rgb image buff address, buff size = width * height * 3
|
|
:param defect_correction: Image parameter used to do defect correction
|
|
:param defect_pos_buffer_address: Defect Pixel position file buffer
|
|
:param defect_pos_buffer_size: Defect Pixel position file buffer size
|
|
|
|
:return: status State return value, See detail in DxStatus
|
|
data_array Array of output images, buff size = width * height * 3
|
|
"""
|
|
if input_address is None:
|
|
raise ParameterTypeError("input_address param is null pointer.")
|
|
|
|
if output_address is None:
|
|
raise ParameterTypeError("output_address param is null pointer.")
|
|
|
|
if not isinstance(defect_correction, StaticDefectCorrection):
|
|
raise ParameterTypeError("StaticDefectCorrection param must be StaticDefectCorrection type.")
|
|
|
|
if defect_pos_buffer_address is None:
|
|
raise ParameterTypeError("defect_pos_buffer_address param is null pointer.")
|
|
|
|
if not isinstance(defect_pos_buffer_size, INT_TYPE):
|
|
raise ParameterTypeError("defect_pos_buffer_size param must be Int type.")
|
|
|
|
status = dx_static_defect_correction(input_address, output_address, defect_correction, defect_pos_buffer_address,
|
|
defect_pos_buffer_size)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("dx_static_defect_correction failure, Error code:%s" % hex(status).__str__())
|
|
|
|
|
|
@staticmethod
|
|
def calcula_lut(contrast_param, gamma, light_ness, lut_address,
|
|
lut_length_address):
|
|
"""
|
|
:brief calculating lookup table of camera
|
|
:param contrast_param: contrast param,range(-50~100)
|
|
:param gamma: gamma param,range(0.1~10)
|
|
:param light_ness: lightness param,range(-150~150)
|
|
:param lut_address: lookup table
|
|
:param lut_length_address: lookup table length(unit:byte)
|
|
|
|
Lookup table length should be obtained through the interface GXGetBufferLength.
|
|
:return: status State return value, See detail in DxStatus
|
|
data_array Array of output images, buff size = width * height * 3
|
|
"""
|
|
if not (isinstance(contrast_param, INT_TYPE)):
|
|
raise ParameterTypeError("contrast_param param must to be int type.")
|
|
|
|
if not (isinstance(gamma, (INT_TYPE, float))):
|
|
raise ParameterTypeError("gamma param must to be int or float type.")
|
|
|
|
if not (isinstance(light_ness, INT_TYPE)):
|
|
raise ParameterTypeError("light_ness param must to be int type.")
|
|
|
|
if lut_address is None:
|
|
raise ParameterTypeError("lut_address is NULL pointer")
|
|
|
|
if lut_length_address is None:
|
|
raise ParameterTypeError("lut_length_address is NULL pointer")
|
|
|
|
status = dx_calc_camera_lut_buffer(contrast_param, gamma, light_ness, lut_address,
|
|
lut_length_address)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("calc_camera_lut_buffer failure, Error code:%s" % hex(status).__str__())
|
|
|
|
@staticmethod
|
|
def read_lut_file(lut_file_path, lut_address, lut_length_address):
|
|
"""
|
|
:brief read lut file
|
|
:param lut_file_path: Lut file path. Lut file(xxx.lut) can be obtained from Lut
|
|
Create Tool Plugin,which can be get by select Plugin->Lut
|
|
Create Tool Plugin from the menu bar in GalaxyView.
|
|
:param lut_address: Lookup table. Users need to apply for memory in advance.The
|
|
memory size is also lookup table length(nLutLength),should be
|
|
obtained through the interface GXGetBufferLength,
|
|
e.g. GXGetBufferLength(m_hDevice, GX_BUFFER_LUT_VALUEALL,&nLutLength),
|
|
:param lut_length_address: Lookup table length(unit:byte),which should be obtained through
|
|
the interface GXGetBufferLength, e.g.
|
|
GXGetBufferLength(m_hDevice, GX_BUFFER_LUT_VALUEALL,&nLutLength),
|
|
:return: status State return value, See detail in DxStatus
|
|
data_array Array of output images, buff size = width * height * 3
|
|
"""
|
|
|
|
if os.path.exists(lut_file_path) is False:
|
|
raise ParameterTypeError("%s file is not exits" % lut_file_path)
|
|
|
|
if lut_address is None:
|
|
raise ParameterTypeError("lut_address is NULL pointer")
|
|
|
|
if lut_length_address is None:
|
|
raise ParameterTypeError("lut_length_address is NULL pointer")
|
|
|
|
path = create_string_buffer(string_encoding(lut_file_path))
|
|
|
|
status = dx_read_lut_file(path, lut_address, lut_length_address)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("read_lut_file failure, Error code:%s" % hex(status).__str__())
|
|
|
|
@staticmethod
|
|
def __is_bayer(pixel_format):
|
|
bayer_gr8_id = (GxPixelFormatEntry.BAYER_GR8 & PIXEL_ID_MASK)
|
|
bayer_bg12_id = (GxPixelFormatEntry.BAYER_BG12 & PIXEL_ID_MASK)
|
|
|
|
bayer_gr16_id = (GxPixelFormatEntry.BAYER_GR16 & PIXEL_ID_MASK)
|
|
bayer_bg16_id = (GxPixelFormatEntry.BAYER_BG16 & PIXEL_ID_MASK)
|
|
if ((pixel_format & PIXEL_ID_MASK) >= bayer_gr8_id) and ((pixel_format & PIXEL_ID_MASK) <= bayer_bg12_id):
|
|
return True
|
|
elif ((pixel_format & PIXEL_ID_MASK) >= bayer_gr16_id) and ((pixel_format & PIXEL_ID_MASK) <= bayer_bg16_id):
|
|
return True
|
|
|
|
return False
|
|
|
|
@staticmethod
|
|
def __is_gray(pixel_format):
|
|
if (pixel_format & PIXEL_COLOR_MASK) != PIXEL_MONO:
|
|
return False
|
|
elif (ImageProcess.__is_bayer(pixel_format)):
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
@staticmethod
|
|
def __get_pixel_color_filter(pixel_format):
|
|
"""
|
|
:brief Calculate pixel color filter based on pixel format
|
|
:param pixel_format
|
|
:return: pixel color filter
|
|
"""
|
|
gr_tup = (GxPixelFormatEntry.BAYER_GR8, GxPixelFormatEntry.BAYER_GR10,
|
|
GxPixelFormatEntry.BAYER_GR12, GxPixelFormatEntry.BAYER_GR16)
|
|
rg_tup = (GxPixelFormatEntry.BAYER_RG8, GxPixelFormatEntry.BAYER_RG10,
|
|
GxPixelFormatEntry.BAYER_RG12, GxPixelFormatEntry.BAYER_RG16)
|
|
gb_tup = (GxPixelFormatEntry.BAYER_GB8, GxPixelFormatEntry.BAYER_GB10,
|
|
GxPixelFormatEntry.BAYER_GB12, GxPixelFormatEntry.BAYER_GB16)
|
|
bg_tup = (GxPixelFormatEntry.BAYER_BG8, GxPixelFormatEntry.BAYER_BG10,
|
|
GxPixelFormatEntry.BAYER_BG12, GxPixelFormatEntry.BAYER_BG16)
|
|
mono_tup = (GxPixelFormatEntry.MONO8, GxPixelFormatEntry.MONO8_SIGNED,
|
|
GxPixelFormatEntry.MONO10, GxPixelFormatEntry.MONO12,
|
|
GxPixelFormatEntry.MONO14, GxPixelFormatEntry.MONO16,
|
|
GxPixelFormatEntry.MONO10_PACKED, GxPixelFormatEntry.MONO12_PACKED)
|
|
|
|
if pixel_format in gr_tup:
|
|
return DxPixelColorFilter.GR
|
|
elif pixel_format in rg_tup:
|
|
return DxPixelColorFilter.RG
|
|
elif pixel_format in gb_tup:
|
|
return DxPixelColorFilter.GB
|
|
elif pixel_format in bg_tup:
|
|
return DxPixelColorFilter.BG
|
|
elif pixel_format in mono_tup:
|
|
return DxPixelColorFilter.NONE
|
|
else:
|
|
return -1
|
|
|
|
@staticmethod
|
|
def __raw_image_process(output_address, image, image_process_config):
|
|
"""
|
|
:brief Raw8 image process
|
|
:param color_img_process_param: image process param, refer to DxColorImgProcess
|
|
:return img_rgb
|
|
"""
|
|
pixel_format = 0
|
|
raw_image_width = 0
|
|
raw_image_height = 0
|
|
input_image_buffer = None
|
|
if isinstance(image, (RawImage, RGBImage)):
|
|
pixel_format = image.frame_data.pixel_format
|
|
raw_image_width = image.frame_data.width
|
|
raw_image_height = image.frame_data.height
|
|
input_image_buffer = image.frame_data.image_buf
|
|
elif isinstance(image, GxImageInfo):
|
|
pixel_format = image.image_pixel_format
|
|
raw_image_width = image.image_width
|
|
raw_image_height = image.image_height
|
|
input_image_buffer = image.image_buf
|
|
else:
|
|
raise ParameterTypeError("image param must be RawImage or GxImageInfo type")
|
|
|
|
if input_image_buffer is None or output_address is None:
|
|
raise ParameterTypeError("input_image_buffer or output_address is NULL pointer")
|
|
|
|
if pixel_format & PIXEL_BIT_MASK != GX_PIXEL_8BIT:
|
|
status = dx_raw16_to_raw8(input_image_buffer, input_image_buffer,
|
|
raw_image_width, raw_image_height,
|
|
image_process_config.get_valid_bits())
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("RawImage.convert: raw16 convert to raw8 failed, Error core: %s"
|
|
% hex(status).__str__())
|
|
|
|
color_filter = ImageProcess.__get_pixel_color_filter(pixel_format)
|
|
mutex = image_process_config.get_mutex()
|
|
with mutex:
|
|
color_img_process_param = image_process_config.get_color_image_process(color_filter)
|
|
status = dx_raw8_image_process(input_image_buffer, output_address,
|
|
raw_image_width, raw_image_height, color_img_process_param)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("RawImage.raw8_image_process: failed, error code:%s" % hex(status).__str__())
|
|
|
|
def __mono_image_process(self, output_address, image, image_process_config):
|
|
"""
|
|
:brief mono8 image process
|
|
:param mono_img_process_param: image process param, refer to DxMonoImgProcess
|
|
:return img_mono
|
|
"""
|
|
pixel_format = 0
|
|
raw_image_width = 0
|
|
raw_image_height = 0
|
|
input_image_buffer = None
|
|
if isinstance(image, (RawImage, RGBImage)):
|
|
pixel_format = image.frame_data.pixel_format
|
|
raw_image_width = image.frame_data.width
|
|
raw_image_height = image.frame_data.height
|
|
input_image_buffer = image.frame_data.image_buf
|
|
elif isinstance(image, GxImageInfo):
|
|
pixel_format = image.image_pixel_format
|
|
raw_image_width = image.image_width
|
|
raw_image_height = image.image_height
|
|
input_image_buffer = image.image_buf
|
|
else:
|
|
raise ParameterTypeError("image param must be RawImage or GxImageInfo type")
|
|
|
|
if input_image_buffer is None or output_address is None:
|
|
raise ParameterTypeError("input_image_buffer or output_address is NULL pointer")
|
|
|
|
if ((pixel_format & PIXEL_BIT_MASK) != GX_PIXEL_8BIT):
|
|
image_temp = None
|
|
output_image_temp = None
|
|
if self.__is_packed_pixel_format(pixel_format):
|
|
self.__check_handle()
|
|
status = dx_image_format_convert_set_output_pixel_format(self.image_convert_handle, GxPixelFormatEntry.MONO8)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_set_output_pixel_format failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
status, out_lenght = dx_image_format_convert_get_buffer_size_for_conversion(self.image_convert_handle, GxPixelFormatEntry.MONO8,
|
|
raw_image_width, raw_image_height)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_get_buffer_size_for_conversion failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
image_temp = (c_ubyte * out_lenght)()
|
|
output_image_temp = addressof(image_temp)
|
|
|
|
status, input_length = dx_image_format_convert_get_buffer_size_for_conversion(self.image_convert_handle, pixel_format,
|
|
raw_image_width, raw_image_height)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"dx_image_format_convert_get_buffer_size_for_conversion failure, Error code:%s" % hex(
|
|
status).__str__())
|
|
|
|
status = dx_image_format_convert(self.image_convert_handle, input_image_buffer, input_length,
|
|
output_image_temp,
|
|
out_lenght, pixel_format,
|
|
raw_image_width, raw_image_height, False)
|
|
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("image_format_convert failure, Error code:%s" % hex(status).__str__())
|
|
else:
|
|
image_temp = (c_ubyte * raw_image_width *raw_image_height)()
|
|
output_image_temp = addressof(image_temp)
|
|
|
|
status = dx_raw16_to_raw8(input_image_buffer, output_image_temp,
|
|
raw_image_width, raw_image_height,
|
|
image_process_config.get_valid_bits())
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("RawImage.convert: raw16 convert to raw8 failed, Error core: %s"
|
|
% hex(status).__str__())
|
|
|
|
input_image_buffer = output_image_temp
|
|
|
|
mutex = image_process_config.get_mutex()
|
|
with mutex:
|
|
mono_img_process_param = image_process_config.get_mono_image_process()
|
|
status = dx_mono8_image_process(input_image_buffer, output_address,
|
|
raw_image_width, raw_image_height, mono_img_process_param)
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError(
|
|
"RawImage.dx_mono8_image_process: failed, error code:%s" % hex(status).__str__())
|
|
|
|
def __check_handle(self):
|
|
"""
|
|
:brief The transformation handle is initialized the first time it is called
|
|
:return NONE
|
|
"""
|
|
if self.image_convert_handle is None:
|
|
status, handle = dx_image_format_convert_create()
|
|
if status != DxStatus.OK:
|
|
raise UnexpectedError("dx_image_format_convert_create failure, Error code:%s" % hex(status).__str__())
|
|
self.image_convert_handle = handle
|
|
|
|
|
|
def __get_pixel_bit(self, pixel_format):
|
|
"""
|
|
:brief get pixel bit
|
|
:return pixel bit
|
|
"""
|
|
return (pixel_format & PIXEL_BIT_MASK)
|
|
|
|
def __is_packed_pixel_format(self, pixel_format):
|
|
"""
|
|
:brief Get whether it is in packed pixel format
|
|
|
|
:return true is packed , false is not packed
|
|
"""
|
|
pixel_bit = self.__get_pixel_bit(pixel_format)
|
|
if (pixel_format & PIXEL_MONO):
|
|
if pixel_bit in (gxipy.GX_PIXEL_10BIT, gxipy.GX_PIXEL_12BIT, gxipy.GX_PIXEL_14BIT,):
|
|
return True
|
|
|
|
return False
|
|
|
|
|