本文参考:https://wenku.csdn.net/answer/7cq5wfccvx
本质:NEDI在双线性插值的基础上,利用各像素点邻域的方差,判断原图上的点是否位于纹理的边界线上。并将边界上的点直接转移到新生成的图中。
简介:
NEDI(New Edge_Directed Interpolation)是一种基于图像边缘信息的图像插值算法。其目标是在差值过程中保存图像的边缘信息。
由于网络上暂时没有NEDI的基于python编写的代码。而目前基于MATLAB的代码有多种版本。本人根据其中一种,编写了一个python版本的代码,可以处理灰白图像。
def nedi(input,new_dimension,side_2,threshold):
(m,n) = input.shape
(N,M) = new_dimension
img_var = np.zeros((m,n))
output = cv2.resize(input,new_dimension,interpolation = cv2.INTER_LINEAR) # 先双线性插值算法
for i in range(m): # 遍历图中所有像素
for j in range(n):
dot = input[i,j] # 框定像素点的领域窗口
dot_x1 = max(0,i-side_2)
dot_x2 = min(i+side_2+1,n)
dot_y1 = max(0,j-side_2)
dot_y2 = min(j+side_2+1,n)
dot_var = np.var(input[dot_x1:dot_x2,dot_y1:dot_y2]) # 计算窗口内的方差
img_var[i,j] = dot_var # 统计各点的方差,方便阈值的调整
if dot_var > threshold: # 判断点的方差是否是边缘点
output[int(i * M / m -0.5),int(j * N / n -0.5)] = dot
return output,img_var # 输出图像与方差图
其中,需要输入的参数除了:原图像、新图像尺寸外,还有窗口大小、方差阈值。为了方便后两者的确定与自适应化。我定义了一个用于装载各点方差的变量:img_var。
效果展示
原图(500*313)
NEDI插值放大后效果图(750,470),窗口:1,阈值:0.5
双线性插值放大后的效果图(750,470)
如图可见,NEDI插值放大法对参数的要求很高。由于时间仓促,没能找到正确的参数与自适应化方法,再此深表歉意。不过,个人认为利用方差确认边界的思路是可取的。
NEDI方差变量img_var的效果图
如图所示,图像的边界被完整地勾勒出来了。
完整代码
import cv2
import matplotlib.pyplot as plt
import numpy as np
import os
import torch
from torchvision.utils import save_image
img = cv2.imread("图像读取地址")
img = img[:,:,0]
height,width = img.shape
#设定通过插值之后图片的size
new_dimension = (750,470)
def img_draw_subplot(subplot_position,img,title_name,cmap): # 绘制图像:(图像位置,图像,标题,输出格式)
plt.subplot(subplot_position)
plt.title(title_name)
plt.imshow(img,cmap)
def image_interpolation(img,new_dimension,inter_method): # 图像二值化:(图像,新图像尺寸,处理方式)
inter_img = cv2.resize(img,new_dimension,interpolation=inter_method)
# a,inter_img = cv2.threshold(inter_img, 0.5, 1.0, cv2.THRESH_BINARY) # 二值化
return inter_img#
#设置cmap
cmap = "gray"
#双线性插值算法,resize函数默认的插值算法
linear_img = image_interpolation(img,new_dimension,cv2.INTER_LINEAR)
img_draw_subplot(233,linear_img,"Linear interpolation",cmap=cmap)
plt.show()
save_image(torch.tensor(linear_img/255), "图像保存地址")
def nedi(input,new_dimension,side_2,threshold):
(m,n) = input.shape
(N,M) = new_dimension
img_var = np.zeros((m,n))
output = cv2.resize(input,new_dimension,interpolation = cv2.INTER_LINEAR) # 先双线性插值算法
for i in range(m): # 遍历图中所有像素
for j in range(n):
dot = input[i,j] # 框定像素点的领域窗口
dot_x1 = max(0,i-side_2)
dot_x2 = min(i+side_2+1,n)
dot_y1 = max(0,j-side_2)
dot_y2 = min(j+side_2+1,n)
dot_var = np.var(input[dot_x1:dot_x2,dot_y1:dot_y2]) # 计算窗口内的方差
img_var[i,j] = dot_var # 统计各点的方差,方便阈值的调整
if dot_var > threshold: # 判断点的方差是否是边缘点
output[int(i * M / m -0.5),int(j * N / n -0.5)] = dot
return output,img_var # 输出图像与方差图
# NEDI差值
side_2 = 1
threshold = 0.5
NEDI_img,NEDI_var = nedi(img,new_dimension,side_2,threshold)
img_draw_subplot(233,NEDI_img,"Linear interpolation",cmap=cmap)
plt.show()
save_image(torch.tensor(NEDI_img/255), "E:/1graduate_mission/ZHU/tools/NEDI/NEDI_1_5.png")
参考的MATLAB代码:(浏览器 搜索词条:NEDI代码实现,可以找到下文代码)
function output_image = nedi_interpolation(input_image)
[m,n] = size(input_image); % 获取输入图像的尺寸
output_image = zeros(2*m,2*n); % 创建一个2倍于输入图像大小的输出图像
for i = 1:m
for j = 1:n
% 获取当前像素的值
current_pixel = input_image(i, j);
% 计算当前像素周围的邻域值(可以根据需要选择邻域大小)
neighborhood = input_image(max(1-1, 1):min(1+1, m), max(j-1, 1):min(j+1, n));
%计算邻域内像素的方差
variance = var(neighborhod(:));
% 判断当前像素是否为边缘点
if variance >threshold % 这里的threshold是一个自定义的阈值
% 如果当前像素是边缘点,则直接将该像素的值赋给输出图像
output image(2*i-1, 2*j-1) = current_pixel;
else
% 如果当前像素不是边缘点,则采用双线性插值计算插值结果
output image(2*i-1, 2*j-1) = current_pixel;
output_image(2*i, 2*j-1) = 0.5 * (current_pixel +input_image(min(i+1, m), j);
output _image(2*i-1, 2*j) = 0.5 * (current_pixel + input_image(i, min(j+1, n));
output_image(2*i, 2*j) = 0.25 * (current_pixel + input_image(i, min(j+1, n)) + input_image(min(j+1, n) + input_image(min(i+1,m),j) + input_image(min(i+1,m),min(j+1, n))
end
end
end
end