图像Python3的中值过滤器 [英] Median filter for image Python3

查看:124
本文介绍了图像Python3的中值过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现一个径向中值滤波器.我有以下图片(大小=(Nx,Ny))

我想导出每个像素的半径.对于每个半径,请计算中间值,并将其放到新矩阵中,以取代所有具有相同半径的像素.我发现使用中值滤镜进行图像平滑,但是速度不够快.而且我创建了自己的脚本,不幸的是,它也不是很快.我在一些常规数据上进行了测试:

import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.image as mpimg
from scipy import stats


a = np.array([[0.,0.,0.,0.,0.],[0.,5.,1.,9.,0.],[0.,10.,2.,10.,0.],[0.,9.,1.,5.,0.],[0.,0.,0.,0.,0.]])

b = a.copy().flatten()

y,x = np.indices((a.shape))
center = [len(x)//2, len(y)//2]
r = np.hypot(x-center[0],y-center[1])

r = r.astype(np.int) # integer part of radii (bin size = 1)

set_r = set(r.flatten()) # get the list of r without duplication
max_r = max(set_r) # determine the maximum r

median_r = np.array([0.]*len(r.flatten())) # array of median I for each r


for j in set_r:
    result = np.where(r.flatten() == j) 
    median_r[result[0]] = np.median(b[result[0]])



a_med = median_r.reshape(a.shape)

am_med = ndimage.median_filter(a, 3)

plt.figure(figsize=(16, 5))

plt.subplot(141)
plt.imshow(a, interpolation='nearest')
plt.axis('off')
plt.title('Original image', fontsize=20)
plt.subplot(142)
plt.imshow(am_med, interpolation='nearest', vmin=0, vmax=5)
plt.axis('off')
plt.title('Median filter', fontsize=20)
plt.subplot(143)
plt.imshow(a_med, interpolation='nearest')
plt.axis('off')
plt.title('Own median', fontsize=20)


plt.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, bottom=0, left=0,
                    right=1)

plt.show()

我想找到一种解决此问题的简便方法

解决方案

我想您要用输入图像中相同半径上的像素均值替换图像每个圆周围的所有像素. /p>

我建议将图像扭曲到笛卡尔坐标,计算平均值,然后扭曲回到极坐标.

我生成了一些像这样的大小的测试数据:

#!/usr/bin/env python3

import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.image as mpimg
from scipy import stats
import numpy as np

w, h = 600, 600
a = np.zeros((h,w),np.uint8)

# Generate some arcs
for s in range(1,6):
    radius = int(s*w/14)
    centre = (int(w/2), int(w/2))
    axes = (radius, radius)
    angle = 360
    startAngle = 0
    endAngle = 72*s

    cv2.ellipse(a, centre, axes, angle, startAngle, endAngle, 255, 2)

这给出了这一点:

Image.fromarray(a.astype(np.uint8)).save('start.png')

def orig(a):
    b = a.copy().flatten()
    y,x = np.indices((a.shape))
    center = [len(x)//2, len(y)//2]
    r = np.hypot(x-center[0],y-center[1])
    r = r.astype(np.int) # integer part of radii (bin size = 1)
    set_r = set(r.flatten()) # get the list of r without duplication
    max_r = max(set_r) # determine the maximum r
    median_r = np.array([0.]*len(r.flatten())) # array of median I for each r
    for j in set_r:
        result = np.where(r.flatten() == j) 
        median_r[result[0]] = np.median(b[result[0]])
    return median_r

def me(a):
    h, w = a.shape
    centre = (int(h/2), int(w/2))
    maxRad = np.sqrt(((h/2.0)**2.0)+((w/2.0)**2.0))
    pol = cv2.warpPolar(a.astype(np.float), a.shape, centre, maxRad, flags=cv2.WARP_POLAR_LINEAR+cv2.WARP_FILL_OUTLIERS)
    polmed = np.median(pol,axis=0,keepdims=True)
    polmed = np.broadcast_to(polmed,a.shape)
    res = cv2.warpPolar(polmed, a.shape, centre,  maxRad, cv2.WARP_INVERSE_MAP)
    return res.astype(np.uint8)

a_med = orig(a).reshape(a.shape)

Image.fromarray(a_med.astype(np.uint8)).save('result.png')

r = me(a)
Image.fromarray(r).save('result-me.png')

结果与您的结果相同,即,它会删除所有小于180度的弧并填充所有超过180度的弧:

但是我的时机快了10倍:

In [58]: %timeit a_med = orig(a).reshape(a.shape)                                                                               
287 ms ± 17.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [59]: %timeit r = me(a)                                                                                                      
29.9 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

如果您很难想象warpPolar()之后我会得到什么,它看起来像这样.然后我用np.mean()取均值,即axis=0:

关键字:Python,径向平均值,径向中值,笛卡尔坐标,极坐标,矩形,warpPolar,linearPolar,OpenCV,图像,图像处理

I wanted to implement a radial median filter. I have the following picture (size = (Nx,Ny))

I want to derive radius for each pixels. For each radius compute median value and put it to a new matrix in the place of all pixels with the same radius. I found Image Smoothing Using Median Filter, but it isn't fast enough. And I created my own script, unfortunately, it isn't fast too. I tested it on some generatic data:

import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.image as mpimg
from scipy import stats


a = np.array([[0.,0.,0.,0.,0.],[0.,5.,1.,9.,0.],[0.,10.,2.,10.,0.],[0.,9.,1.,5.,0.],[0.,0.,0.,0.,0.]])

b = a.copy().flatten()

y,x = np.indices((a.shape))
center = [len(x)//2, len(y)//2]
r = np.hypot(x-center[0],y-center[1])

r = r.astype(np.int) # integer part of radii (bin size = 1)

set_r = set(r.flatten()) # get the list of r without duplication
max_r = max(set_r) # determine the maximum r

median_r = np.array([0.]*len(r.flatten())) # array of median I for each r


for j in set_r:
    result = np.where(r.flatten() == j) 
    median_r[result[0]] = np.median(b[result[0]])



a_med = median_r.reshape(a.shape)

am_med = ndimage.median_filter(a, 3)

plt.figure(figsize=(16, 5))

plt.subplot(141)
plt.imshow(a, interpolation='nearest')
plt.axis('off')
plt.title('Original image', fontsize=20)
plt.subplot(142)
plt.imshow(am_med, interpolation='nearest', vmin=0, vmax=5)
plt.axis('off')
plt.title('Median filter', fontsize=20)
plt.subplot(143)
plt.imshow(a_med, interpolation='nearest')
plt.axis('off')
plt.title('Own median', fontsize=20)


plt.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, bottom=0, left=0,
                    right=1)

plt.show()

I'd like to find a convenient way for solving this issue

解决方案

I think you want to replace all pixels around the radius of each circle of the image with the mean of the pixels on that same radius in the input image.

I propose to warp the image to cartesian coordinates, calculate the mean and then warp back to polar coordinates.

I generated some test data of a decent size like this:

#!/usr/bin/env python3

import cv2
from PIL import Image
from scipy import stats, ndimage, misc
import matplotlib.image as mpimg
from scipy import stats
import numpy as np

w, h = 600, 600
a = np.zeros((h,w),np.uint8)

# Generate some arcs
for s in range(1,6):
    radius = int(s*w/14)
    centre = (int(w/2), int(w/2))
    axes = (radius, radius)
    angle = 360
    startAngle = 0
    endAngle = 72*s

    cv2.ellipse(a, centre, axes, angle, startAngle, endAngle, 255, 2)

That gives this:

Image.fromarray(a.astype(np.uint8)).save('start.png')

def orig(a):
    b = a.copy().flatten()
    y,x = np.indices((a.shape))
    center = [len(x)//2, len(y)//2]
    r = np.hypot(x-center[0],y-center[1])
    r = r.astype(np.int) # integer part of radii (bin size = 1)
    set_r = set(r.flatten()) # get the list of r without duplication
    max_r = max(set_r) # determine the maximum r
    median_r = np.array([0.]*len(r.flatten())) # array of median I for each r
    for j in set_r:
        result = np.where(r.flatten() == j) 
        median_r[result[0]] = np.median(b[result[0]])
    return median_r

def me(a):
    h, w = a.shape
    centre = (int(h/2), int(w/2))
    maxRad = np.sqrt(((h/2.0)**2.0)+((w/2.0)**2.0))
    pol = cv2.warpPolar(a.astype(np.float), a.shape, centre, maxRad, flags=cv2.WARP_POLAR_LINEAR+cv2.WARP_FILL_OUTLIERS)
    polmed = np.median(pol,axis=0,keepdims=True)
    polmed = np.broadcast_to(polmed,a.shape)
    res = cv2.warpPolar(polmed, a.shape, centre,  maxRad, cv2.WARP_INVERSE_MAP)
    return res.astype(np.uint8)

a_med = orig(a).reshape(a.shape)

Image.fromarray(a_med.astype(np.uint8)).save('result.png')

r = me(a)
Image.fromarray(r).save('result-me.png')

The result is the same as yours, i.e. it removes all arcs less than 180 degrees and fills all arcs over 180 degrees:

But the timing for mine is 10x faster:

In [58]: %timeit a_med = orig(a).reshape(a.shape)                                                                               
287 ms ± 17.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [59]: %timeit r = me(a)                                                                                                      
29.9 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In case you are having difficulty imagining what I get after warpPolar(), it looks like this. Then I use np.mean() to take the mean down the columns, i.e. axis=0:

Keywords: Python, radial mean, radial median, cartesian coordinates, polar coordinates, rectangular, warpPolar, linearPolar, OpenCV, image, image processing

这篇关于图像Python3的中值过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆