def ri(ID, bayerformat="rggb", pedestal=64, bitdepth=10, custom_source=None): if custom_source is None: IDyuv = preprocess(ID, bayerformat=bayerformat, pedestal=pedestal, bitdepth=bitdepth, outputformat="yuv") else: IDyuv = custom_source IDy = IDyuv[:, :, 0] h, w = IDy.shape roiSize = 0.025 # define centre locations for ROI roiCentreX = [0.5, 0.0125, 0.9875, 0.0125, 0.9875] roiCentreY = [0.5, 0.0125, 0.0125, 0.9875, 0.9875] # generate data for all ROIs ri = np.zeros(len(roiCentreX)) ri_mean = [] for i in range(len(ri)): x1 = int(np.round(w * roiCentreX[i] - (w * roiSize / 2) + 0.5)) x2 = int(np.round(w * roiCentreX[i] + (w * roiSize / 2) - 1.4999)) y1 = int(np.round(h * roiCentreY[i] - (h * roiSize / 2) + 0.5)) y2 = int(np.round(h * roiCentreY[i] + (h * roiSize / 2) - 1.4999)) ri_mean.append(np.mean(np.mean(IDy[y1:y2 + 1, x1:x2 + 1]))) ri = 100 * (ri_mean / ri_mean[0]) ri_delta = np.max(ri[1:5]) - np.min(ri[1:5]) return ri, ri_delta
def di(ID, bayerformat="rggb", pedestal=64, bitdepth=10, custom_source=None): if custom_source is None: IDyuv = preprocess(ID, bayerformat=bayerformat, pedestal=pedestal, bitdepth=bitdepth, outputformat="yuv") else: IDyuv = custom_source IDy = IDyuv[:, :, 0] h, w = IDy.shape slope = h / w slope_back = -slope diag = [] back_diag = [] for i in range(w): # diag y = (slope * i) big = int(np.ceil(y)) little = int(y) if big != little: diag.append(np.mean(IDy[little:big + 1, i])) else: diag.append(np.mean(IDy[little, i])) # back-diag y_back = (slope_back * i + h) big_back = int(np.ceil(y_back)) little_back = int(y_back) if big != little: back_diag.append(np.mean(IDy[little_back:big_back + 1, i])) else: back_diag.append(np.mean(IDy[little, i])) # normalize the data diag = np.array(diag) back_diag = np.array(back_diag) diag = diag / np.max(diag) back_diag = back_diag / np.max(back_diag) return diag, back_diag
def dp(IDraw, bayerformat="rggb", pedestal=64, bitdepth=10, threshold_defect=0.19, threshold_defectLow=0.12, threshold_detectable=32, cluster_type="bayer", cluster_size=3, neighbour_type="avg", more_precise=False): if threshold_defect > 1: ID = preprocess(IDraw, bayerformat, outputformat="raw", mode=0, bitdepth=bitdepth, pedestal=pedestal, FOV=0, whitebalance=False, signed=True, more_precise=more_precise) else: ID = preprocess(IDraw, bayerformat, outputformat="raw", mode=0, bitdepth=bitdepth, pedestal=pedestal, FOV=0, whitebalance=True, signed=True, more_precise=more_precise) h = ID.shape[0] w = ID.shape[1] # 初始化变量 count_cluster = 0 count_DP = 0 count_NDP = 0 count_NDPP = 0 roi_size = 15 # 对四个边缘进行填补(延展长度roiSize / 2) ID_mirror = np.pad(ID, roi_size - 1, "symmetric") h_mirror = ID_mirror.shape[0] w_mirror = ID_mirror.shape[1] """ 由于padding是对称的 所以 |--| |RG| |GB| |--| padding后就是 GB RG |--| GR|RG|GR BG|GB|BG |--| GB RG 所以奇偶互换才能变回 RG GB |--| RG|RG|RG GB|GB|GB |--| RG GB """ # 对奇偶行进行交换 ID_mirror[[1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12], :] = ID_mirror[ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], :] ID_mirror[ [-13, -14, -11, -12, -9, -10, -7, -8, -5, -6, -3, -4, -1, -2 ], :] = ID_mirror[ [-14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1], :] # 对奇偶列进行交换 ID_mirror[:, [1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12 ]] = ID_mirror[:, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]] ID_mirror[:, [-13, -14, -11, -12, -9, -10, -7, -8, -5, -6, -3, -4, -1, -2 ]] = ID_mirror[:, [ -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1 ]] # 把图像进行均值归一化 ID_avg = np.zeros(ID_mirror.shape) kernel = np.zeros((2 * roi_size - 1, 2 * roi_size - 1)) kernel[::2, ::2] = 1 / (roi_size**2) ID_avg = correlate(ID_mirror, kernel) # 去除多余边框,恢复原分辨率 ID_avg = ID_avg[roi_size - 1:h_mirror - roi_size + 1, roi_size - 1:w_mirror - roi_size + 1] # 找出defective pixels if threshold_defect > 1: ID_delta = ID - ID_avg # LSB(Least significant bit) 值,最小有效值,黑场(dark field)测试条件 map_defect = (np.abs(ID_delta) > threshold_defect).astype( np.double) # 求出大于threshold的布尔坐标图,转换为double(0或1) else: # 计算差异百分比 ID_percDiff = np.abs((ID - ID_avg) / ID_avg) ID_percDiff[np.isnan(ID_percDiff)] = 0 # 把所有0/0的无效值替换为0 ID_delta = ID_percDiff map_defect = (np.abs(ID_delta) > threshold_defect).astype( np.double) # 求出大于threshold的布尔坐标图,转换为double(0或1) ID_delta = ID_delta * 100 # 小数转百分比 # 定义kernel # 1.簇(cluster)内核 # 当内核对应点的值,大于100 + cluster_size - 1的时候,该点就被标记为cluster的中心。后期增长(grow)cluster的时候,内核会被再次应用 if cluster_type is "bayer": cluster_pattern = np.array([[1, 0, 1, 0, 1], [0, 0, 0, 0, 0], [1, 0, 100, 0, 1], [0, 0, 0, 0, 0], [1, 0, 1, 0, 1]]) elif cluster_type is "raw": cluster_pattern = np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 100, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]) # 2.梯对(ladder pair)内核 ladder_pattern = np.array([[0, 1, 0, 1, 0], [0, 0, 0, 0, 0], [0, 1, 33, 1, 0], [0, 0, 0, 0, 0], [0, 1, 0, 1, 0]]) # 3.对(pair)内核 pair_pattern = np.array([[1, 0, 1, 0, 1], [0, 0, 0, 0, 0], [1, 0, 33, 0, 1], [0, 0, 0, 0, 0], [1, 0, 1, 0, 1]]) # 4.行(row)内核 row_pattern = np.array([[0, 0, 0, 0, 0], [1, 1, 1, 1, 1], [0, 0, 33, 0, 0], [1, 1, 1, 1, 1], [0, 0, 0, 0, 0]]) # 1.簇(cluster)检测 # 检测cluster defects,并标记cluster里面的所有像素 map_temp_cluster = conv2(map_defect, cluster_pattern) # 应用卷积 map_temp_cluster = (np.abs(map_temp_cluster) >= (100 + cluster_size - 1)).astype(np.double) map_temp_cluster = conv2(map_temp_cluster, cluster_pattern) # 再次应用卷积,找出影响区 map_temp_cluster = map_temp_cluster * map_defect # 标出影响区里面的所有像素(看看defective pixels是否与cluster有交集) map_temp_cluster = (map_temp_cluster > 0).astype(np.double) # 筛选出无cluster的区域(排除cluster的影响进行下一步检测) map_no_cluster = map_defect - map_temp_cluster # 2.边界2行2列的defects检测 map_temp_border = np.ones(ID.shape) map_temp_border[2:h - 2, 2:w - 2] = 0 map_temp_border = map_no_cluster * map_temp_border """ 怕不是DP Tagging修补dp的源码,但是缺乏defectivePixel_featureScore_Apple,暂时无法使用 remove all NVM locations featureScoreスキップのため無効化 the code below will iterate through all NVM locations and set those as non-defects for i=1:size(nvm,1) nvm_x = nvm(i,1); nvm_y = nvm(i,2); if (nvm_y >= 3) && (nvm_y <= (h-2)) && (nvm_x >=3) && (nvm_x <= (w-2)) kernel = mapTemp_cluster((nvm_y-2):(nvm_y+2),(nvm_x-2):(nvm_x+2)); else kernel = zeros(5,5); end Check for valid image coordinates if ((nvm_y >=1) && (nvm_y <= h) && (nvm_x >= 1) && (nvm_x <=w)) Check for tagged cluster if (defectivePixel_featureScore_Apple(kernel, 2) <= nvm_clusterSize) mapTemp_cluster(nvm_y, nvm_x) = 0; end map_noCluster(nvm_y,nvm_x) = 0; else Do nothing end end """ # 把非cluster的DP标记出来,从而标记DP/DPP/NDP/NDPP # Detectable Pixel/Detectable Pixel Pair/Detectable Pixel Pair/Non-Detectable Pixel Pair (temp_y, temp_x) = np.where(map_no_cluster > 0) map_temp_detection = np.zeros(ID.shape) for i in range(0, len(temp_y)): # 提取周围的3x3同色区域,注意,同色 bayer_neighbour3_y = np.arange(temp_y[i] - 2, temp_y[i] + 3, 2) bayer_neighbour3_x = np.arange(temp_x[i] - 2, temp_x[i] + 3, 2) # 创建坐标对 bayer_neighbour = np.transpose( np.vstack((np.tile(bayer_neighbour3_y, 3), np.repeat(bayer_neighbour3_x, 3)))) bayer_neighbour = np.delete(bayer_neighbour, 4, axis=0) bayer_neighbour = bayer_neighbour[bayer_neighbour[:, 0] >= 0, :] bayer_neighbour = bayer_neighbour[bayer_neighbour[:, 0] < h, :] bayer_neighbour = bayer_neighbour[bayer_neighbour[:, 1] >= 0, :] bayer_neighbour = bayer_neighbour[bayer_neighbour[:, 1] < w, :] # 获取对应像素值 temp_ROI = np.sort(ID[bayer_neighbour[:, 0], bayer_neighbour[:, 1]]) if neighbour_type is "avg": temp_ROI = temp_ROI[1:-1] # 去除极大极小值 temp_avg = np.mean(temp_ROI) temp_neighbour = np.abs(ID[temp_y[i], temp_x[i]] - temp_avg) elif neighbour_type is "delta": temp_diff = np.abs(temp_ROI - ID[temp_y, temp_x]) temp_neighbour = np.min(temp_diff) # 根据差异来判断 if temp_neighbour > threshold_detectable: map_temp_detection[temp_y[i], temp_x[i]] = 3 else: map_temp_detection[temp_y[i], temp_x[i]] = 1 # 标记DP/DPP/NDP/NDPP/Border defects map_temp_conv = conv2(map_temp_detection, pair_pattern) map_temp_DP = (map_temp_conv == 99).astype(np.double) # 浮点布尔图 map_temp_NDP = (map_temp_conv == 33).astype(np.double) # 浮点布尔图 map_temp_DPP = ((map_temp_conv != 99) * (map_temp_conv > 35)).astype( np.double) # 浮点布尔图,DPP中心 map_temp_NDPP = (map_temp_conv == 34).astype(np.double) # 浮点布尔图,NDPP中心 # 标记DLP/NLP(NDLP) # Detectable Ladder Pixel/ Non-detectable Ladder Pixel map_temp_conv = conv2(map_temp_detection, ladder_pattern) map_temp_DLP = ((map_temp_conv != 99) * (map_temp_conv > 35)).astype( np.double) # 浮点布尔图 map_temp_NLP = (map_temp_conv == 34).astype(np.double) # 浮点布尔图 # 标记ARPD(Adjacent row pair defects) if cluster_type is "bayer" and threshold_defect >= 1: map_temp_conv = np.zeros(ID.shape) else: map_temp_conv = conv2(map_temp_detection, row_pattern) map_temp_ARPD = ((map_temp_conv > 33) * (map_temp_conv != 99)).astype( np.double) # 浮点布尔图,标记ARPD的中心 # 标记low contrast cluster低对比度簇(仅限光场) map_temp_clusterlow = np.zeros(ID.shape) if threshold_defect <= 1: # 光场条件下 map_defect_low = (np.abs(ID_delta) > (threshold_defectLow * 100)).astype(np.double) map_defect_low = map_defect_low - map_defect # 当内核对应点的值,大于100 + cluster_size - 1的时候,该点就被标记为clusterlow的中心。后期增长(grow)cluster的时候,内核会被再次应用 cluster_pattern = np.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 100, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]) # 找出低对比度簇 map_temp_clusterlow = conv2(map_defect_low, cluster_pattern) map_temp_clusterlow = (map_temp_clusterlow >= (100 + cluster_size - 1)).astype(np.double) map_temp_clusterlow = conv2(map_temp_clusterlow, cluster_pattern) map_temp_clusterlow = map_temp_clusterlow * map_defect_low map_temp_clusterlow = (map_temp_clusterlow > 0).astype(np.double) """ Feature功能尚未加入 """ mapFail = np.max( np.dstack(( map_temp_DP, 2 * map_temp_DPP, 3 * map_temp_border, # 4 * map_temp_feature, 5 * map_temp_NDP, 6 * map_temp_NDPP, 7 * map_temp_DLP, 8 * map_temp_NLP, 9 * map_temp_ARPD, 10 * map_temp_cluster, 11 * map_temp_clusterlow)), axis=2) DP_data = [ np.where(mapFail == 1), len((np.where(mapFail == 1))[0]), ID_percDiff[np.where(mapFail == 1)] ] DPP_data = [np.where(mapFail == 2), len((np.where(mapFail == 2))[0]) / 2] NDP_data = [np.where(mapFail == 5), len((np.where(mapFail == 5))[0])] NDPP_data = [np.where(mapFail == 6), len((np.where(mapFail == 6))[0]) / 2] DLP_data = [np.where(mapFail == 7), len((np.where(mapFail == 7))[0]) / 2] NLP_data = [np.where(mapFail == 8), len((np.where(mapFail == 8))[0]) / 2] feature_data = [np.where(mapFail == 4), len((np.where(mapFail == 4))[0])] ARPD_data = [np.where(mapFail == 9), len((np.where(mapFail == 9))[0]) / 2] cluster_data = [np.where(mapFail == 10), len((np.where(mapFail == 10))[0])] clusterlow_data = [ np.where(mapFail == 11), len((np.where(mapFail == 11))[0]) ] border_data = [np.where(mapFail == 3), len((np.where(mapFail == 3))[0])] all_dp_data = [ np.where(mapFail > 0), len((np.where(mapFail > 0))[0]), ID_percDiff[np.where(mapFail == 1)] ] dp_fail_result = [ DP_data, DPP_data, NDP_data, NDPP_data, DLP_data, NLP_data, feature_data, ARPD_data, cluster_data, clusterlow_data, border_data, all_dp_data ] dp_pointset = [] for i in range(len(dp_fail_result[-1][0][0])): dp_pointset.append( (dp_fail_result[-1][0][1][i], dp_fail_result[-1][0][0][i])) return dp_fail_result, dp_pointset, ID
import datetime import argparse import cv2 import numpy as np import imutils from io_bin.preprocess import preprocess ap = argparse.ArgumentParser() ap.add_argument("-i", "--imageinput", required=True, help="path to the raw image") ap.add_argument("--inputbayerformat", type=str, default="rggb", help="bayerformat of input image data") ap.add_argument("-o", "--outputformat", type=str, default="raw", help="format of output image data") ap.add_argument("-p", "--pedestal", type=int, default=64, help="amount of pedestal to add") ap.add_argument("-m", "--mode", type=int, default=2, help="crop mode") ap.add_argument("-f", "--FOV", type=int, default=0, help="Field of view") ap.add_argument("-w", "--whitebalance", type=bool, default=True, help="whether apply whitebalance") ap.add_argument("-b", "--bitdepth", type=int, default=10, help="depth of the color") ap.add_argument("-s", "--signed", type=bool, default=True, help="Whether all pixels value will be signed") args = vars(ap.parse_args()) time1 = datetime.datetime.now() # ID = preprocess(imageinput=args["imageinput"], outputformat="rgb", mode=2, FOV=75, whitebalance=True, more_precise=True) ID = preprocess(imageinput=args["imageinput"], custom_size=[3856, 2340], custom_encoding="B") cv2.imshow("RAW", imutils.resize(ID.astype(np.uint8), width=600)) cv2.waitKey() time2 = datetime.datetime.now() print(time2 - time1)
def black_dot_location(self, detect_thresh_val=5, center_area_percentage=0.3, bayerformat="rggb", pedestal=64, bitdepth=10, custom_size=[3856, 2340], debug=False): raw_rgb = preprocess(self.raw_file, outputformat="rgb", more_precise=True, custom_size=[3856, 2340], custom_encoding="B") raw_rgb = (raw_rgb / 4).astype(np.uint8) raw_gray = cv2.cvtColor(raw_rgb, cv2.COLOR_BGR2GRAY) self.height, self.width = raw_gray.shape[:2] black_dot_map = (raw_gray <= (np.min(raw_gray) + detect_thresh_val)).astype( np.uint8) black_dot_map[black_dot_map != 0] = 255 black_dot_edge = auto_canny(black_dot_map) cnts = cv2.findContours(black_dot_edge, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2] cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5] # cv2.drawContours(raw_rgb, cnts, -1, (255, 0, 255), -1) # center, upperleft, upperright, lowerright, lowerleft black_dot_ori = [] for c in cnts: ((x, y), radius) = cv2.minEnclosingCircle(c) if debug: cv2.circle(raw_rgb, (int(x), int(y)), int(radius), (255, 0, 255), 2) black_dot_ori.append((x, y)) # print(radius) black_dot_ori = np.array(black_dot_ori) # determine the corners # center delta_width = np.abs(black_dot_ori[:, 0] - self.width / 2) self.black_dot[0] = black_dot_ori[np.argmin(delta_width)] # ul and lr s = black_dot_ori.sum(axis=1) self.black_dot[1] = black_dot_ori[np.argmin(s)] self.black_dot[3] = black_dot_ori[np.argmax(s)] # ll and ur diff = np.diff(black_dot_ori, axis=1) self.black_dot[2] = black_dot_ori[np.argmin(diff)] self.black_dot[4] = black_dot_ori[np.argmax(diff)] if debug: for i in range(len(self.black_dot)): cv2.putText( raw_rgb, str(i + 1), (int(self.black_dot[i][0]), int(self.black_dot[i][1])), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 255), 5) cv2.imshow("Diagram", imutils.resize(raw_rgb, width=800)) return self.black_dot, raw_rgb
help="amount of pedestal to add") ap.add_argument("-m", "--mode", type=int, default=2, help="crop mode") ap.add_argument("-f", "--FOV", type=int, default=0, help="Field of view") ap.add_argument("-w", "--whitebalance", type=bool, default=True, help="whether apply whitebalance") ap.add_argument("-b", "--bitdepth", type=int, default=10, help="depth of the color") ap.add_argument("-s", "--signed", type=bool, default=True, help="Whether all pixels value will be signed") args = vars(ap.parse_args()) time1 = datetime.datetime.now() ID = preprocess(imageinput=args["imageinput"], outputformat="rgb", mode=0, FOV=75, whitebalance=True, more_precise=True) time2 = datetime.datetime.now() print(time2 - time1)
def oc(IDraw, bayerformat="rggb", pedestal=64, bitdepth=10, custom_source=None): if custom_source is None: IDyuv = preprocess(IDraw, bayerformat=bayerformat, pedestal=pedestal, bitdepth=bitdepth, outputformat="yuv") else: IDyuv = custom_source IDy = IDyuv[:, :, 0] (h, w) = IDy.shape h_center = h / 2 + 0.5 - 1 w_center = w / 2 + 0.5 - 1 roi_size = 100 roi_size_half = roi_size / 2 # 定义ROI中心区 # [中,顶,右,底,左] roi_center_x = [ w_center, w_center, w_center + h_center - (roi_size_half + 0.5) + 1, w_center, w_center - h_center + roi_size_half + 0.5 - 1 ] roi_center_y = [ h_center, roi_size_half + 0.5 - 1, h_center, h - (roi_size_half - 0.5) - 1, h_center ] threshold_data = np.zeros(len(roi_center_x)) for i in range(len(threshold_data)): x1 = int(roi_center_x[i] - (roi_size_half - 0.5)) x2 = int(roi_center_x[i] + (roi_size_half - 0.5)) y1 = int(roi_center_y[i] - (roi_size_half - 0.5)) y2 = int(roi_center_y[i] + (roi_size_half - 0.5)) threshold_data[i] = np.mean(IDy[y1:y2 + 1, x1:x2 + 1]) # 计算并应用二值化(threshold) oc_threshold = np.mean([threshold_data[0], np.mean(threshold_data[1:])]) # 通过中心与周围四点,求出二值化的阀值 ID_threshold_binary = (IDy >= oc_threshold).astype( np.double) # 浮点布尔图,False为暗,True为亮 # 计算重心 total_points = int(np.sum(ID_threshold_binary)) row_weight = np.arange(1, h + 1) col_weight = np.arange(1, w + 1) row_sum = np.sum(ID_threshold_binary, axis=1) * row_weight col_sum = np.sum(ID_threshold_binary, axis=0) * col_weight oc_x = np.sum(col_sum) / total_points oc_y = np.sum(row_sum) / total_points oc_x_shift = oc_x - (IDy.shape[1] / 2 + 0.5) oc_y_shift = (IDy.shape[0] / 2 + 0.5) - oc_y # 半径 oc_mag_shift = np.sqrt(oc_x_shift**2 + oc_y_shift**2) oc_result = [ oc_threshold, oc_x, oc_y, oc_x_shift, oc_y_shift, oc_mag_shift ] return oc_result, IDyuv