OpenCV中的反卷积?

9

有没有使用OpenCV进行反卷积的方法?

我对这里展示的改进印象深刻。

from https://web.archive.org/web/20160402174700/http://www.olympusmicro.com/primer/digitalimaging/deconvolution/images/deconalgorithmsfigure1.jpg

我希望将这个功能添加到我的软件中。
编辑(奖励的额外信息):
我仍然没有弄清楚如何实现反卷积。这段代码帮助我锐化图像,但我认为反卷积可能会做得更好。
void ImageProcessing::sharpen(QImage & img)
{
    IplImage* cvimg = createGreyFromQImage( img );
    if ( !cvimg ) return;

    IplImage* gsimg = cvCloneImage(cvimg );
    IplImage* dimg = cvCreateImage( cvGetSize(cvimg), IPL_DEPTH_8U, 1 );
    IplImage* outgreen = cvCreateImage( cvGetSize(cvimg), IPL_DEPTH_8U, 3 );
    IplImage* zeroChan = cvCreateImage( cvGetSize(cvimg), IPL_DEPTH_8U, 1 );
    cvZero(zeroChan);

    cv::Mat smat( gsimg, false );
    cv::Mat dmat( dimg, false );

    cv::GaussianBlur(smat, dmat, cv::Size(0, 0), 3);
    cv::addWeighted(smat, 1.5, dmat, -0.5 ,0, dmat);
    cvMerge( zeroChan, dimg, zeroChan, NULL, outgreen);

    img = IplImage2QImage( outgreen );
    cvReleaseImage( &gsimg );
    cvReleaseImage( &cvimg );
    cvReleaseImage( &dimg );
    cvReleaseImage( &outgreen );
    cvReleaseImage( &zeroChan );
}

希望能得到有用的提示!

要求编写代码的问题必须显示出对所解决问题的基本理解。包括尝试过的解决方案、为什么不起作用以及期望的结果。另请参阅:Stack Overflow问题清单。 - dhein
2
在这个主题上发现了一篇有趣的文章:http://yuzhikov.com/articles/BlurredImagesRestoration1.htm - Valentin H
4个回答

9
当然,您可以使用OpenCV编写去卷积代码。但是目前还没有现成的函数(尚未)。
要开始操作,您可以查看此示例,其中展示了使用OpenCV在Python中实现Wiener去卷积的实现:https://github.com/opencv/opencv/blob/master/samples/python/deconvolution.py 这里是另一个示例,使用C语言,但是这是2012年的内容,所以可能已过时:https://www.ibm.com/developerworks/community/blogs/theTechTrek/entry/experiments_with_deblurring_using_opencv1?lang=en

谢谢。看起来比我预期的要复杂得多。第二个例子很简单,应该可以理解并重写为OpenCV2。我会等待一些时间以获取其他建议(可能使用其他方法,如最近邻反卷积),如果没有其他内容,则选择您的建议。 - Valentin H
最终,我已经学会了足够运行第一个示例的Python知识。对于汽车图像的结果令人惊讶。我相信甚至可以通过运动分析(所有小线都朝同一方向)和图像的某些上下文信息来确定PSF。然而,在我的图像(显微镜中的细胞)上,结果并不那么好。可能我没有正确配置PFS,这并不像在汽车示例中那样明显。 - Valentin H
了解您的点扩散函数(PSF)非常重要,如果不了解您的PSF,则反卷积将是一项非常困难的任务(因为您必须猜测)。也许如果您详细描述拍摄图像的设置,人们可以帮助您。 - Mailerdaimon
好的,我会添加信息。实际上,我的方向是Z。这可能意味着,PSF不能从一张图像中定义,而是需要在显微镜在同一位置上移动时捕获的图像堆栈中定义。我认为这在我当前的问题描述中并不清楚。 - Valentin H

6
Nearest neighbor deconvolution是一种在光学显微镜的Z平面图像堆栈上通常使用的技术。这篇评论文章:Jean-Baptiste Sibarita. Deconvolution Microscopy. Adv Biochem Engin/Biotechnol (2005) 95: 201–243涵盖了许多使用的技术,包括您感兴趣的技术。这也是一个不错的介绍:http://blogs.fe.up.pt/BioinformaticsTools/microscopy/ 这个numpy+scipy python示例展示了它的工作原理:
from pylab import *
import numpy
import scipy.ndimage

width = 100
height = 100
depth = 10
imgs = zeros((height, width, depth))

# prepare test input, a stack of images which is zero except for a point which has been blurred by a 3D gaussian
#sigma = 3
#imgs[height/2,width/2,depth/2] = 1
#imgs = scipy.ndimage.filters.gaussian_filter(imgs, sigma)

# read real input from stack of images img_0000.png, img_0001.png, ... (total number = depth)
# these must have the same dimensions equal to width x height above
# if imread reads them as having more than one channel, they need to be converted to one channel
for k in range(depth):
    imgs[:,:,k] = scipy.ndimage.imread( "img_%04d.png" % (k) )

# prepare output array, top and bottom image in stack don't get filtered
out_imgs = zeros_like(imgs)
out_imgs[:,:,0] = imgs[:,:,0]
out_imgs[:,:,-1] = imgs[:,:,-1]

# apply nearest neighbor deconvolution
alpha = 0.4 # adjustabe parameter, strength of filter
sigma_estimate = 3 # estimate, just happens to be same as the actual

for k in range(1, depth-1):
    # subtract blurred neighboring planes in the stack from current plane
    # doesn't have to be gaussian, any other kind of blur may be used: this should approximate PSF
    out_imgs[:,:,k] = (1+alpha) * imgs[:,:,k]  \
        - (alpha/2) * scipy.ndimage.filters.gaussian_filter(imgs[:,:,k-1], sigma_estimate) \
        - (alpha/2) * scipy.ndimage.filters.gaussian_filter(imgs[:,:,k+1], sigma_estimate)

# show result, original on left, filtered on right
compare_img = copy(out_imgs[:,:,depth/2])
compare_img[:,:width/2] = imgs[:,:width/2,depth/2]
imshow(compare_img)
show()

太酷了!谢谢你提供的链接!我会在接下来的几天里阅读这些链接,测试代码,并很可能给你奖励。顺便说一句:与此同时,我正在考虑将Python嵌入到我的应用程序中,或者将所有图像处理功能移至一个用Python实现的独立进程中。有这么多强大的包可供选择... - Valentin H
抱歉,我刚开始学习Python。你能帮忙用真实图像测试代码吗?我尝试了img = scipy.ndimage.imread("19756782_g.png"),其中png是灰度8位图像。然后我将这样的图像放入集合/数组imgs中。不幸的是,在k的循环中,我得到了错误“'tuple' object has no attribute 'shape'”,其范围为1到imgs.shape[2]-1。 - Valentin H
@ValentinHeinitz:这个示例对你有用吗?请查看上面更新的代码,如果你有更多问题,请告诉我。 - Alex I
@ValentinHeinitz 你已经在OpenCV中实现了这个功能吗?无论是确定PSF还是Wiener去卷积? - salgarcia
@salgarcia:到目前为止还没有。我的显微镜Z轴定位/对焦/校准算法有一些实现细节,这使我无法在实践中应用去卷积。我已经将此功能推迟到下一个版本发布。实际上,正如Mailerdaimon所提到的,在opencv2的python示例中,Wiener去卷积效果良好。 - Valentin H
显示剩余3条评论

4
您提供的示例图像实际上是Lucy-Richardson去卷积的很好的示例。在OpenCV库中没有这种去卷积方法的内置函数。在Matlab中,您可以使用“deconvlucy.m”函数进行去卷积。实际上,通过输入“open”或“edit”,您可以在Matlab中查看一些函数的源代码。 下面,我尝试在OpenCV中简化Matlab代码。
// Lucy-Richardson Deconvolution Function
// input-1 img: NxM matrix image
// input-2 num_iterations: number of iterations
// input-3 sigma: sigma of point spread function (PSF)
// output result: deconvolution result

// Window size of PSF
int winSize = 10 * sigmaG + 1 ;

// Initializations
Mat Y = img.clone();
Mat J1 = img.clone();
Mat J2 = img.clone();
Mat wI = img.clone(); 
Mat imR = img.clone();  
Mat reBlurred = img.clone();    

Mat T1, T2, tmpMat1, tmpMat2;
T1 = Mat(img.rows,img.cols, CV_64F, 0.0);
T2 = Mat(img.rows,img.cols, CV_64F, 0.0);

// Lucy-Rich. Deconvolution CORE

double lambda = 0;
for(int j = 0; j < num_iterations; j++) 
{       
    if (j>1) {
        // calculation of lambda
        multiply(T1, T2, tmpMat1);
        multiply(T2, T2, tmpMat2);
        lambda=sum(tmpMat1)[0] / (sum( tmpMat2)[0]+EPSILON);
        // calculation of lambda
    }

    Y = J1 + lambda * (J1-J2);
    Y.setTo(0, Y < 0);

    // 1)
    GaussianBlur( Y, reBlurred, Size(winSize,winSize), sigmaG, sigmaG );//applying Gaussian filter 
    reBlurred.setTo(EPSILON , reBlurred <= 0); 

    // 2)
    divide(wI, reBlurred, imR);
    imR = imR + EPSILON;

    // 3)
    GaussianBlur( imR, imR, Size(winSize,winSize), sigmaG, sigmaG );//applying Gaussian filter 

    // 4)
    J2 = J1.clone();
    multiply(Y, imR, J1);

    T2 = T1.clone();
    T1 = J1 - Y;
}

// output
result = J1.clone();

这是一些示例和结果。 enter image description here enter image description here Lucy-Richardson去卷积的实例结果 访问我的博客这里,你可以获得整个代码。

你的博客很棒!! - Jeru Luke

3
我不确定你是否理解反卷积的概念。反卷积的想法是从图像中去除探测器响应。这在天文学中很常见。
例如,如果你在望远镜上安装了一个CCD相机,那么你拍摄的任何图像都是你观察到的天空和光学系统响应的卷积。望远镜(或摄像头镜头等)将具有一些点扩散函数(PSF)。也就是说,如果你看着一个非常遥远的点源(如一颗星),当你拍摄它的图像时,该星将模糊多个像素。这种模糊 - 点扩散 - 是你想要去除的。如果你非常了解你的光学系统的点扩散函数,那么你可以将PSF从图像中反卷积并获得更清晰的图像。
除非你恰好知道你的光学系统的PSF(难以测量!),否则你应该寻找其他选项来锐化你的图像。我怀疑OpenCV是否内置了Richardson-Lucy算法之类的东西。

感谢您提到Richardson-Lucy算法。同时,我已经基本上理解了您描述的反卷积过程。不幸的是,Alex I发布的示例对我的图像无效,因为我的PSF不是高斯模糊。在尝试使用未经模糊处理的图像堆栈测试自动对焦算法时,我也遇到了PSF。它没有起作用,SO上的某个人指向了我“PSF”。 - Valentin H
1
如果您想使用反卷积,您需要测量光学系统的PSF。我想您可以猜测它,但那样就像摸黑一样。要测量它,您需要在视野中的各个点成像白光点源。光学PSF通常被近似为高斯函数,但您至少需要知道分布的宽度。实际上,除非您愿意测量您的PSF,否则我强烈建议您寻找另一个锐化算法。 - Scott Griffiths

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接