赞
踩
import numpy as np import os import random import cv2 from skimage.morphology import binary_dilation, binary_erosion # pip install scikit-image """ 移走水印 """ def hist_match(source, template, ignore_black = True): """分层直方图匹配(源,模板,忽略_黑色=真)""" cv2.imshow('source',source) cv2.imshow('template',template) """ https://stackoverflow.com/questions/32655686/histogram-matching-of-two-images-in-python-2-x 图像的匹配-2-x 调整灰度图像的像素值,使其直方图与目标图像的匹配 Adjust the pixel values of a grayscale image such that its histogram matches that of a target image Arguments: ----------- source: np.ndarray 要转换的图像;直方图是在展平的数组 Image to transform; the histogram is computed over the flattened array template: np.ndarray 模板图像;可以有不同的来源维度 Template image; can have different dimensions to source Returns: ----------- matched: np.ndarray The transformed output image """ oldshape = source.shape source = source.ravel()#源=源行程 template = template.ravel() # get the set of unique pixel values and their corresponding indices and # counts s_values, bin_idx, s_counts = np.unique(source, return_inverse=True,return_counts=True) if ignore_black: s_counts[0] = 0 t_values, t_counts = np.unique(template, return_counts=True)#去除数组中的重复数字,并进行排序之后输出 if ignore_black: t_counts[0] = 0 # take the cumsum of the counts and normalize by the number of pixels to # get the empirical cumulative distribution functions for the source and # template images (maps pixel value --> quantile) s_quantiles = np.cumsum(s_counts).astype(np.float64)#s_分位数= np。累计总和 s_quantiles /= s_quantiles[-1] t_quantiles = np.cumsum(t_counts).astype(np.float64) t_quantiles /= t_quantiles[-1] # interpolate linearly to find the pixel values in the template image # that correspond most closely to the quantiles in the source image interp_t_values = np.interp(s_quantiles, t_quantiles, t_values)#一维线性插值函数。 returned_image = interp_t_values[bin_idx].reshape(oldshape) return returned_image.astype(np.uint8) def coloured_image_to_edge_mark(coloured_image): # 彩色图像到边缘标记 image_sum = coloured_image[:,:,0] + coloured_image[:,:,1] + coloured_image[:,:,2] mask = image_sum > 0 return mask def triple_mask(mask):#三重掩码(掩码) return np.stack( [mask]* 3, axis = 2) def get_inner_and_outer_masks(mask): inner_mask = binary_erosion(binary_erosion(binary_dilation(mask)))#内部掩码=腐蚀(腐蚀(膨胀()) inner_pixel_count = np.count_nonzero(inner_mask)#内部_像素_计数= np.count _非零(内部_掩码) #inner_mask = mask outer_mask = binary_dilation(binary_dilation(mask)) #外部掩码=膨胀(膨胀(谈吗)) #无颜色异常 no colour abnormaility outer_pixel_count = np.count_nonzero(outer_mask)#外部像素计数= np.count _非零(外部掩码) print("inner_pixel_coint = ",inner_pixel_count)#inner_pixel_coint = 114356 print("outer_pixel_count = ",outer_pixel_count) return inner_mask, outer_mask def balance_histograms_using_v(inner, outer): """ make RGB image inner have the same brightness (i.e. v) histogram as image outer """ inner_v_before, inner_hsv = rgb_to_intensity(inner)#rgb _ to _强度 outer_v, outer_hsv = rgb_to_intensity(outer)#rgb _ to _强度 inner_v_after = hist_match(inner_v_before, outer_v) inner_hsv[:,:,2] = inner_v_after # edit V channel only return cv2.cvtColor(inner_hsv, cv2.COLOR_HSV2BGR) # return as BGR def fill_in(io, edge_mask, outer_mask): """ http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_photo/py_inpainting/py_inpainting.html """ fill_in_method = cv2.INPAINT_TELEA # other choice cv2.INPAINT_NS - makes little visible difference # 算法基于Bertalmio,Marcelo,Andrea L.Bertozzi和Guillermo Sapiro于2001年发表“Navier - Stokes, 流体动力学与图像和视频修补”大作。 # 算法基于流体动力学,采用偏微分方程,原则幽默heurisitic。首先沿已知区域边缘行进到未知区域(边缘连续)。 # 照片继续(连接相同强度点成线,类似轮廓 连接相同高度点), # 并在修复区域边界处--匹配渐变矢量。获得颜色后,填充颜色--以减少该区域最小差异。使用标志:cv2.INPAINT_NS启用此算法。 io_hsv = rgb_to_hsv(io) h_before = io_hsv[:,:,0] s_before = io_hsv[:,:,1] v_before = io_hsv[:,:,2] outer_mask_uint = np.where(outer_mask,255,0).astype(np.uint8) s_after = cv2.inpaint(s_before, outer_mask_uint, 15, fill_in_method) # use outer mask to fill in saturation h_after = cv2.inpaint(h_before, outer_mask_uint, 15 ,fill_in_method) # use outer mask to fill in hue v_after = cv2.inpaint(v_before, edge_mask, 2, fill_in_method) # use edge to fill in hue io_hsv[:,:,0] = h_after io_hsv[:,:,1] = s_after io_hsv[:,:,2] = v_after return hsv_to_rgb(io_hsv) def rgb_to_hsv(im): # HSV 颜色空间转换 RGB 颜色空间,重塑为圆柱体 而不是立方体,亮度是单独维度 # - Hue:色调,检查哪种“纯”颜色。例如“红色”颜色所有阴影和色调都将--具有相同色调。 [0, 179] # - Saturation:饱和度,颜色有多“白”。完全饱和的颜色将是“纯色”,如“纯红色”。零饱和度的颜色将是纯白色。 [0, 255] # - Value:值允许控制颜色的亮度。值为零表示纯黑色,而增加值会产生较浅的颜色。 [0, 255] # 转换图像为HSV颜色空间并展示 return cv2.cvtColor(im, cv2.COLOR_BGR2HSV)#颜色转换为hsv def hsv_to_rgb(im): return cv2.cvtColor(im, cv2.COLOR_HSV2BGR) def rgb_to_intensity(im): """rgb _ to _强度""" hsv = rgb_to_hsv(im)#获取某维度 return hsv[:,:,2], hsv def make_random_colour_map_with_stats(stats, pop_thresh = 0): n = len(stats)#统计数 colour_map = np.zeros( [n, 3], dtype=np.uint8) #给定形状和类型的用0填充的数组 for i in range(n): if ( (pop_thresh != 0) and (stats[i][4] < pop_thresh) ) or (i == 0): # 将小区域和区域0(背景)设为黑色 colour_map[i] = [0,0,0] # make small regions and region 0 (background) black else: for j in range(3): # 大区域是非零的随机颜色 colour_map[i,j] = 1 + random.randint(0,254) # big regions are a non-zero random colou return colour_map """ Image comes from here https://www.architecture.com/image-library/RIBApix/licensed-image/poster/balintore-castle-angus-the-entrance-front/posterid/RIBA65186.html """ def display_and_output_image(name, im):#显示和输出图像 cv2.imshow(name,im) file_name = os.path.join( "C:\\Users\\david\\Desktop\\", name + ".jpg") cv2.imwrite(file_name,im) def create_letter_mask(image_saturation): """ https://stackoverflow.com/questions/35854197/how-to-use-opencvs-connected-components-with-stats-in-python threshold saturation to detect letters (low saturation) 检测字母的阈值饱和度(低饱和度) find big connected components (small connected components are noise) 查找大的连接组件(小的连接组件是噪音) # 创建字母掩码 """ connectivity = 4 #连通性 #阈值(image_saturation,) ret, thresh_s = cv2.threshold(image_saturation, 42, 255, cv2.THRESH_BINARY_INV) # 50 too high, 25 too low # cv2.THRESH_OTSU 最小二乘法,cv2.THRESH_TRIANGLE三角算法。cv2.THRESH_OTSU适合双峰图;cv2.THRESH_TRIANGLE适合单峰图。 output = cv2.connectedComponentsWithStats(thresh_s, connectivity, cv2.CV_32S)# 处理不规则连通区域 # depth:矩阵元素一个通道数据类型,值和type相关。如type为CV_16SC2,一个2通道16位有符号整数。 blob_image = output[1]#滴图像 液滴;黏稠的一滴;色斑;色点;形状不易确定的一团;零分 stats = output[2]#统计数据 pop_thresh = 60# 弹出或流行 # 大斑点颜色图=制造随机颜色图用统计 big_blob_colour_map = make_random_colour_map_with_stats(stats, pop_thresh) all_blob_colour_map = make_random_colour_map_with_stats(stats)#所有斑点颜色图 big_blob_coloured_image = big_blob_colour_map[blob_image]# 大块颜色图 # output all_blob_coloured_image = all_blob_colour_map[blob_image]#所有块颜色图 # output display_and_output_image("big_blob_coloured_image", big_blob_coloured_image)#显示图像 display_and_output_image("all_blob_coloured_image", all_blob_coloured_image) letter_mask = coloured_image_to_edge_mark(big_blob_coloured_image)#字母掩码=彩色图像到边缘标记 return letter_mask#字母掩码 def main(): """ original image comes from here https://www.architecture.com/image-library/RIBApix/licensed-image/poster/balintore-castle-angus-the-entrance-front/posterid/RIBA65186.html """ im = cv2.imread("mark1.jpg")#读取原始图 print (im.shape)#(422, 640, 3) display_and_output_image("image",im)#显示图片 hsv = rgb_to_hsv(im)#转换为hsv image_saturation = hsv[:,:,1] # 图像饱和度output display_and_output_image("image_saturation",image_saturation)#显示饱和度,并写入一个文件 letter_mask = create_letter_mask(image_saturation) #字母掩码 # outer mask bigger than letter mask # inner mask smaller than letter mask # edge mask is between inner and outer mask and contains black line round letters (i.e. to be removed) inner_mask, outer_mask = get_inner_and_outer_masks(letter_mask)#获取内部和外部掩码 edge_mask = np.logical_and( np.logical_not(inner_mask), outer_mask) #边缘掩码= (内部掩码),外部掩码) edge_mask = np.where(edge_mask,255,0).astype(np.uint8) display_and_output_image("edge_mask",edge_mask) #显示和输出图像 inner_image = np.where( triple_mask(inner_mask), im, 0)#condition:array_like,bool ,当为True时,产生x,否则产生y outer_image = np.where( triple_mask(outer_mask) ,0 ,im) cv2.imwrite('inner_image.jpg',inner_image) cv2.imwrite('outer_image.jpg',outer_image) # 平衡_内部_图像 = 平衡_直方图_使用_v(内部_图像,外部_图像) balanced_inner_image = balance_histograms_using_v(inner_image,outer_image) cv2.imwrite('balanced_inner_image.jpg',balanced_inner_image) before_filling_in = balanced_inner_image + outer_image #填充前=平衡的内部图像+外部图像 display_and_output_image("before_filling_in",before_filling_in) cv2.imwrite('sss.jpg',before_filling_in) after_filling_in = fill_in(before_filling_in, edge_mask, outer_mask) #填充后=填充(前填充、边缘掩码、外部遮罩) # output display_and_output_image("after_filling_in",after_filling_in) cv2.waitKey(0) cv2.destroyAllWindows() if __name__ == '__main__': main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。