def demosaicing_CFA_Bayer_bilinear(raw: RawImageInfo, output): """ Bilinear Bayer CFA Demosaicing ============================== *Bayer* CFA (Colour Filter Array) bilinear demosaicing. References ---------- - :cite:`Losson2010c` : Losson, O., Macaire, L., & Yang, Y. (2010). Comparison of Color Demosaicing Methods. In Advances in Imaging and Electron Physics (Vol. 162, pp. 173-265). doi:10.1016/S1076-5670(10)62005-8 """ R_m, G_m, B_m = raw.masks_CFA_Bayer() CFA = raw.get_raw_data() H_G = np.float32( [[0, 1, 0], [1, 4, 1], [0, 1, 0]]) * 0.25 H_RB = np.float32( [[1, 2, 1], [2, 4, 2], [1, 2, 1]]) * 0.25 output[:, :, 2] = convolve(CFA * R_m, H_RB) output[:, :, 1] = convolve(CFA * G_m, H_G) output[:, :, 0] = convolve(CFA * B_m, H_RB) del R_m, G_m, B_m, H_RB, H_G return
def __init__(self, parmas, process_bar=None): self.old_pipeline = [] self.pipeline = [] self.params = parmas # img_list存储了pipeline中途所有的图像 # img_list长度比pipeline长1 self.img_list = [RawImageInfo()] self.process_bar = process_bar self.imglist_mutex = Lock() self.ispProcthread = ISPProc(self.params, self.img_list, self.imglist_mutex)
def pipeline_reset(self): """ func: 重新开始一个pipeline,把以前的图像清除 """ if(len(self.img_list) > 1): self.imglist_mutex.acquire() self.img_list = [RawImageInfo()] self.imglist_mutex.release() self.old_pipeline = [] self.pipeline = [] return True return False
def __init__(self, name='RawImageEditor', parent=None): super().__init__(name, parent, Ui_ImageEditor(), need_processBar=True) self.scene = QGraphicsScene() self.imageview = ImageView(self.scene, parent) self.img_params = RawImageParams() self.img_params = self.load_params(RawImageParams()) self.img_pipeline = IspPipeline(self.img_params, process_bar=self.progress_bar) self.img = RawImageInfo() self.point_data = np.array([0]) self.scale_ratio = 100 self.show_img = None self.select_awb = False self.histView = None # 由于graphicsView被自定义了,需要重新定义一下UI,gridlayout还需要重新加一下widget self.ui.graphicsView.addWidget(self.imageview, 0, 1, 3, 1) self.imageview.sigDragEvent.connect(self.__init_img) self.imageview.sigMouseMovePoint.connect(self.show_point_rgb) self.imageview.sigWheelEvent.connect(self.update_wheel_ratio) # 回调函数初始化 self.ui.pipeline.doubleClicked.connect(self.update_img_index) self.ui.pipeline_ok.clicked.connect(self.update_pipeline) self.ui.open_image.clicked.connect(self.open_image) self.ui.analysis_img.clicked.connect(self.openHistView) self.ui.select_from_raw.clicked.connect(self.select_awb_from_raw) self.imageview.rubberBandChanged.connect(self.update_awb_from_raw) self.ui.save_image.clicked.connect(self.save_now_image) self.ui.reload.clicked.connect(self.img_pipeline.reload_isp) self.ui.inputflatphoto.clicked.connect( self.img_params.rolloff.set_flatphoto) # ISP 处理线程回调 self.img_pipeline.ispProcthread.doneCB.connect(self.update_img) self.img_pipeline.ispProcthread.processRateCB.connect( self.update_process_bar) self.img_pipeline.ispProcthread.costTimeCB.connect( self.update_time_bar) self.img_pipeline.ispProcthread.errorCB.connect(self.error_report)
def get_image(self, index): """ func: 获取pipeline中的一幅图像 如果输入-1,则返回最后一幅图像 """ ret_img = None self.imglist_mutex.acquire() if (index < len(self.img_list) and index >= 0): ret_img = self.img_list[index] elif (index < 0 and len(self.pipeline) + 1 + index < len(self.img_list)): ret_img = self.img_list[len(self.pipeline) + 1 + index] self.imglist_mutex.release() if (ret_img is not None): return ret_img else: return RawImageInfo()
def demosaic(raw: RawImageInfo, params: RawImageParams): """ function: demosaic input: raw:RawImageInfo() params:RawImageParams() demosaic有两种算法,设置demosaic的算法 0: Malvar-He-Cutler algorithm 1: directionally weighted gradient based interpolation algorithm """ ret_img = RawImageInfo() ret_img.create_image('after demosaic', raw, depth=3) if (params.get_demosaic_funct_type() == 0): demosaicing_CFA_Bayer_bilinear(raw, ret_img.data) elif (params.get_demosaic_funct_type() == 1): demosaicing_CFA_Bayer_Malvar2004(raw, ret_img.data) elif (params.get_demosaic_funct_type() == 2): demosaicing_CFA_Bayer_Menon2007(raw, ret_img.data) else: return None ret_img.clip_range() ret_img.set_color_space("RGB") return ret_img
def demosaicing_CFA_Bayer_Malvar2004(raw: RawImageInfo, output): """ *Bayer* CFA (Colour Filter Array) *Malvar (2004)* demosaicing. References ---------- - :cite:`Malvar2004a` : Malvar, H. S., He, L.-W., Cutler, R., & Way, O. M. (2004). High-Quality Linear Interpolation for Demosaicing of Bayer-Patterned Color Images. International Conference of Acoustic, Speech and Signal Processing, 5-8. http://research.microsoft.com/apps/pubs/default.aspx?id=102068 """ R_m, G_m, B_m = raw.masks_CFA_Bayer() CFA = raw.get_raw_data() GR_GB = np.float32( [[0, 0, -1, 0, 0], [0, 0, 2, 0, 0], [-1, 2, 4, 2, -1], [0, 0, 2, 0, 0], [0, 0, -1, 0, 0]]) * 0.125 Rg_RB_Bg_BR = np.float32( [[0, 0, 0.5, 0, 0], [0, -1, 0, -1, 0], [-1, 4, 5, 4, - 1], [0, -1, 0, -1, 0], [0, 0, 0.5, 0, 0]]) * 0.125 Rg_BR_Bg_RB = np.transpose(Rg_RB_Bg_BR) Rb_BB_Br_RR = np.float32( [[0, 0, -1.5, 0, 0], [0, 2, 0, 2, 0], [-1.5, 0, 6, 0, -1.5], [0, 2, 0, 2, 0], [0, 0, -1.5, 0, 0]]) * 0.125 R = CFA * R_m G = CFA * G_m B = CFA * B_m del G_m G = np.where(np.logical_or(R_m == 1, B_m == 1), convolve(CFA, GR_GB), G) RBg_RBBR = convolve(CFA, Rg_RB_Bg_BR) RBg_BRRB = convolve(CFA, Rg_BR_Bg_RB) RBgr_BBRR = convolve(CFA, Rb_BB_Br_RR) del GR_GB, Rg_RB_Bg_BR, Rg_BR_Bg_RB, Rb_BB_Br_RR # Red rows. R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape, dtype=np.float32) # Red columns. R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape, dtype=np.float32) # Blue rows. B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape, dtype=np.float32) # Blue columns B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape, dtype=np.float32) del R_m, B_m R = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_RBBR, R) R = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_BRRB, R) B = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_RBBR, B) B = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_BRRB, B) R = np.where(np.logical_and(B_r == 1, B_c == 1), RBgr_BBRR, R) B = np.where(np.logical_and(R_r == 1, R_c == 1), RBgr_BBRR, B) del RBg_RBBR, RBg_BRRB, RBgr_BBRR, R_r, R_c, B_r, B_c output[:, :, 2] = R output[:, :, 1] = G output[:, :, 0] = B del R,G,B return
def demosaicing_CFA_Bayer_Menon2007(raw: RawImageInfo, output): """ DDFAPD - Menon (2007) Bayer CFA Demosaicing =========================================== *Bayer* CFA (Colour Filter Array) DDFAPD - *Menon (2007)* demosaicing. References ---------- - :cite:`Menon2007c` : Menon, D., Andriani, S., & Calvagno, G. (2007). Demosaicing With Directional Filtering and a posteriori Decision. IEEE Transactions on Image Processing, 16(1), 132-141. doi:10.1109/TIP.2006.884928 """ R_m, G_m, B_m = raw.masks_CFA_Bayer() CFA = raw.get_raw_data() h_0 = np.array([0, 0.5, 0, 0.5, 0], dtype=np.float32) h_1 = np.array([-0.25, 0, 0.5, 0, -0.25], dtype=np.float32) R = CFA * R_m G = CFA * G_m B = CFA * B_m G_H = np.where(G_m == 0, _cnv_h(CFA, h_0) + _cnv_h(CFA, h_1), G) G_V = np.where(G_m == 0, _cnv_v(CFA, h_0) + _cnv_v(CFA, h_1), G) C_H = np.where(R_m == 1, R - G_H, 0) C_H = np.where(B_m == 1, B - G_H, C_H) C_V = np.where(R_m == 1, R - G_V, 0) C_V = np.where(B_m == 1, B - G_V, C_V) D_H = np.abs(C_H - np.pad(C_H, ((0, 0), (0, 2)), mode=str('reflect'))[:, 2:]) D_V = np.abs(C_V - np.pad(C_V, ((0, 2), (0, 0)), mode=str('reflect'))[2:, :]) del h_0, h_1, CFA, C_V, C_H k = np.array( [[0, 0, 1, 0, 1], [0, 0, 0, 1, 0], [0, 0, 3, 0, 3], [0, 0, 0, 1, 0], [0, 0, 1, 0, 1]], dtype=np.float32) d_H = convolve(D_H, k, mode='constant') d_V = convolve(D_V, np.transpose(k), mode='constant') del D_H, D_V mask = d_V >= d_H G = np.where(mask, G_H, G_V) M = np.where(mask, 1, 0) del d_H, d_V, G_H, G_V # Red rows. R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape, dtype=np.float32) # Blue rows. B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape, dtype=np.float32) k_b = np.array([0.5, 0, 0.5], dtype=np.float32) R = np.where( np.logical_and(G_m == 1, R_r == 1), G + _cnv_h(R, k_b) - _cnv_h(G, k_b), R, ) R = np.where( np.logical_and(G_m == 1, B_r == 1) == 1, G + _cnv_v(R, k_b) - _cnv_v(G, k_b), R, ) B = np.where( np.logical_and(G_m == 1, B_r == 1), G + _cnv_h(B, k_b) - _cnv_h(G, k_b), B, ) B = np.where( np.logical_and(G_m == 1, R_r == 1) == 1, G + _cnv_v(B, k_b) - _cnv_v(G, k_b), B, ) R = np.where( np.logical_and(B_r == 1, B_m == 1), np.where( M == 1, B + _cnv_h(R, k_b) - _cnv_h(B, k_b), B + _cnv_v(R, k_b) - _cnv_v(B, k_b), ), R, ) B = np.where( np.logical_and(R_r == 1, R_m == 1), np.where( M == 1, R + _cnv_h(B, k_b) - _cnv_h(R, k_b), R + _cnv_v(B, k_b) - _cnv_v(R, k_b), ), B, ) del k_b, R_r, B_r del M, R_m, G_m, B_m output[:, :, 2] = R output[:, :, 1] = G output[:, :, 0] = B del R,G,B return
class RawImageEditor(SubWindow): def __init__(self, name='RawImageEditor', parent=None): super().__init__(name, parent, Ui_ImageEditor(), need_processBar=True) self.scene = QGraphicsScene() self.imageview = ImageView(self.scene, parent) self.img_params = RawImageParams() self.img_params = self.load_params(RawImageParams()) self.img_pipeline = IspPipeline(self.img_params, process_bar=self.progress_bar) self.img = RawImageInfo() self.point_data = np.array([0]) self.scale_ratio = 100 self.show_img = None self.select_awb = False self.histView = None # 由于graphicsView被自定义了,需要重新定义一下UI,gridlayout还需要重新加一下widget self.ui.graphicsView.addWidget(self.imageview, 0, 1, 3, 1) self.imageview.sigDragEvent.connect(self.__init_img) self.imageview.sigMouseMovePoint.connect(self.show_point_rgb) self.imageview.sigWheelEvent.connect(self.update_wheel_ratio) # 回调函数初始化 self.ui.pipeline.doubleClicked.connect(self.update_img_index) self.ui.pipeline_ok.clicked.connect(self.update_pipeline) self.ui.open_image.clicked.connect(self.open_image) self.ui.analysis_img.clicked.connect(self.openHistView) self.ui.select_from_raw.clicked.connect(self.select_awb_from_raw) self.imageview.rubberBandChanged.connect(self.update_awb_from_raw) self.ui.save_image.clicked.connect(self.save_now_image) self.ui.reload.clicked.connect(self.img_pipeline.reload_isp) self.ui.inputflatphoto.clicked.connect( self.img_params.rolloff.set_flatphoto) # ISP 处理线程回调 self.img_pipeline.ispProcthread.doneCB.connect(self.update_img) self.img_pipeline.ispProcthread.processRateCB.connect( self.update_process_bar) self.img_pipeline.ispProcthread.costTimeCB.connect( self.update_time_bar) self.img_pipeline.ispProcthread.errorCB.connect(self.error_report) def error_report(self, value): """ func: 报告ISP算法错误 """ critical(value, self) def update_img(self): """ func: ISP 处理完成后的显示回调函数 """ self.displayImage(self.img_pipeline.get_image(-1)) def update_process_bar(self, value): """ func: ISP 处理进度回调 """ self.progress_bar.setValue(value) def update_time_bar(self, value): """ func:ISP 处理时长回调 """ self.time_bar.setText(value) def show(self): """ func: 显示初始化 """ super().show() self.img_params.set_img_params_ui(self.ui) self.ui.filename.repaint() if (self.img_params.rawformat.filename != ""): self.update_pipeline() self.img = self.img_pipeline.get_image(-1) self.displayImage(self.img) self.rect = [ 0, 0, self.img_params.rawformat.width, self.img_params.rawformat.height ] def displayImage(self, img): """ 显示图像 输入需要是RawImageInfo """ self.scene.clear() self.img = img self.show_img = img.get_showimage() if (self.show_img is not None): showimg = QImage(self.show_img, self.show_img.shape[1], self.show_img.shape[0], QImage.Format_BGR888) self.scene.addPixmap(QPixmap(showimg)) self.ui.photo_title.setTitle(img.get_name()) if (self.histView is not None and self.histView.enable is True): self.histView.update_rect_data(self.show_img, self.rect) def select_awb_from_raw(self): """ func: 进入raw图选择模式,修改鼠标类型 """ self.imageview.setDragMode(QGraphicsView.RubberBandDrag) self.select_awb = True def update_awb_from_raw(self, viewportRect, fromScenePoint, toScenePoint): """ func: 鼠标选中事件的回调:执行AWB的选择区域或者图像分析的选择区域 """ if (toScenePoint.x() == 0 and toScenePoint.y() == 0 and self.rect[2] > self.rect[0] and self.rect[3] > self.rect[1]): if (self.select_awb == True): self.imageview.setDragMode(QGraphicsView.ScrollHandDrag) self.select_awb = False awb_ratio = self.img.get_raw_img_rect(self.rect) if (awb_ratio is not None): self.img_params.awb.set_awb_ratio(awb_ratio) awb_gain = self.img_params.awb.get_awb_gain() self.ui.awb_r.setValue(awb_gain[0]) self.ui.awb_g.setValue(awb_gain[1]) self.ui.awb_b.setValue(awb_gain[2]) else: critical("请在raw图上进行选择") else: if (self.histView is not None): self.histView.update_rect_data(self.show_img, self.rect) else: self.rect = [ int(fromScenePoint.x()), int(fromScenePoint.y()), int(toScenePoint.x()), int(toScenePoint.y()) ] def update_pipeline(self): """ func: 运行ISP pipeline """ self.img_params.get_img_params(self.ui) self.img_pipeline.pipeline_clear() for i in range(self.ui.pipeline.count()): if (self.ui.pipeline.item(i).checkState() == Qt.Checked): self.img_pipeline.add_pipeline_node( self.ui.pipeline.item(i).data(0)) self.img_pipeline.run_pipeline() def update_img_index(self, item): """ func: 更新当前画面的序号 """ if (self.ui.pipeline.item(item.row()).checkState() == Qt.Checked): index = self.img_pipeline.get_pipeline_node_index(item.data()) + 1 self.displayImage(self.img_pipeline.get_image(index)) def open_image(self): """ func: 打开图片的回调函数 """ if (self.img_params.rawformat.filename != ''): now_path = os.path.dirname(self.img_params.rawformat.filename) else: now_path = './' imagepath = QFileDialog.getOpenFileName(None, '打开RAW图', now_path, "raw (*.raw)") self.__init_img(imagepath[0]) def __init_img(self, filename): if (filename != ''): self.ui.filename.setText(filename) self.ui.filename.repaint() self.update_pipeline() self.img = self.img_pipeline.get_image(-1) self.rect = [ 0, 0, self.img_params.rawformat.width, self.img_params.rawformat.height ] def save_now_image(self): """ func: 保存图片的回调 """ if (self.img.get_raw_data() is not None): imagepath = QFileDialog.getSaveFileName(None, '保存图片', './', "Images (*.jpg)") if (imagepath[0] != ""): self.img.save_image(imagepath[0]) def show_point_rgb(self, point): """ func: 鼠标移动的回调 """ self.x = int(point.x()) self.y = int(point.y()) if (self.img.get_raw_data() is not None): point_data = self.img.get_img_point(self.x, self.y) if (point_data is not None): self.point_data = point_data self.set_img_info_show() def update_wheel_ratio(self, ratio): """ func: 鼠标滚轮的回调 """ if (self.img.get_raw_data() is not None): self.scale_ratio = int(ratio * 100) self.set_img_info_show() def set_img_info_show(self): """ func: 显示像素点的值以及缩放比例 """ if (self.point_data.size == 1): self.info_bar.setText("x:{},y:{} : {}: 亮度:{} 缩放比例:{}%".format( self.x, self.y, self.img.get_img_point_pattern(self.y, self.x).upper(), self.point_data, self.scale_ratio)) elif (self.point_data.size == 3): if (self.img.get_color_space() == 'RGB'): self.info_bar.setText( "x:{},y:{} : R:{} G:{} B:{} 缩放比例:{}%".format( self.x, self.y, self.point_data[2], self.point_data[1], self.point_data[0], self.scale_ratio)) else: self.info_bar.setText( "x:{},y:{} : Y:{} Cr:{} Cb:{} 缩放比例:{}%".format( self.x, self.y, self.point_data[0], self.point_data[1], self.point_data[2], self.scale_ratio)) def openHistView(self): self.histView = HistView(self.imageview) rect = [0, 0, self.show_img.shape[1], self.show_img.shape[0]] self.histView.update_rect_data(self.show_img, rect) self.histView.show()