图像处理时用的卷积函数

  做图像处理,最耗时间的运算应该就是卷积运算那一步了。以后如果有机会在用c++做图像处理的项目的话,那么这个卷积部分还是要优化的。Matlab因为是验证算法,其实是没必要优化的。所以我就把卷积这一部分单独列出一个函数,用汇编实现了。我可是电子工程出身,汇编当然不在话下。

  函数是用汇编写的,用的是c++内嵌asm汇编,相同功能的c++代码也实现了,不过注释掉了,去掉注释能得到相同的结果。

  读和显示图像用了opencv函数库,话说上一个项目结束之后好像就没怎么用过这个库了,毕竟,单单调用库中的函数是没办法真正理解原理的。

#include <iostream>
#include "cv.h"
#include "highgui.h"
using namespace std;

//*img是图像数据,i_h是图像的高,i_w是图像的宽
//*m是卷积模板,m_h是模板的高,m_w是模板的宽
//x,y是在图像(x,y)坐标处卷积
//返回卷积的值
int conv(int *img,int i_h,int i_w,int *m,int m_h,int m_w,int y,int x)
{
    int re;
    int sum1;
    int sum2;
    int half_m_w;
    int half_m_h;
    int i;
    int j;
    int ii;
    int jj;
    __asm
    {
        mov        re,0;
        mov        sum1,0;
        mov        sum2,0;

        mov        eax,m_w;        //half_m_w=(m_w-1)/2;
        dec        eax;
        mov        bl,2;
        div        bl;
        mov        ah,0;
        mov        half_m_w,eax;

        mov        eax,m_h;        //half_m_h=(m_h-1)/2;
        dec        eax;
        mov        bl,2;
        div        bl;
        mov        ah,0;
        mov        half_m_h,eax;

        mov        ecx,m_w;        //m_w*h_h
        imul      ecx,m_h;
        mov        eax,0;

label1:
        mov        ebx,m;            //        for (i=0;i<m_w*m_h;i++)                                                                                                                    
        add        eax,[ebx];        //        {
        add        ebx,4;            //            sum2+=m[i];
        dec        ecx;            //        }
        jnz        label1;
        mov        sum2,eax;

        mov        i,0;
        mov        ii,0;
        mov        eax,y;            //i=y-half_m_h;
        sub        eax,half_m_h;
        mov        i,eax;

label2:
        mov        j,0;
        mov        jj,0;
        mov        eax,x;            //j=x-half_m_w;
        sub        eax,half_m_w;
        mov        j,eax;

label3:        
        mov        ebx,img;        //每次循环重新赋值img基址
        mov        edx,m;            //每次重新赋值m基址

        mov        eax,i;            //i*i_w+j
        imul    eax,4;
        imul    eax,i_w;
        mov        ecx,j;
        imul    ecx,4;
        add        eax,ecx;
        add        ebx,eax;

        mov        eax,ii;            //ii*m_w+jj
        imul      eax,4;
        imul      eax,m_w;
        mov        ecx,jj;
        imul      ecx,4;
        add        eax,ecx;
        add        edx,eax;

        mov        eax,[ebx];        //sum1+=img[i*i_w+j]*m[ii*m_w+jj];
        imul      eax,[edx];
        add        eax,sum1;
        mov        sum1,eax;

        mov        eax,jj;            //jj++
        inc        eax;
        mov        jj,eax;

        mov        eax,x;            //j?<x+half_m_w
        add        eax,half_m_w;
        mov        ecx,eax;
        sub        ecx,j;
        mov        eax,j;            //j++
        inc        eax;
        mov        j,eax;

        test      ecx,ecx;
        jnz        label3;
         
        mov        eax,ii;            //ii++
        inc        eax;
        mov        ii,eax;

        mov        eax,y;            //i?<y+half_m_h
        add        eax,half_m_h;
        mov        ecx,eax;
        sub        ecx,i;
        mov        eax,i;            //i++
        inc        eax;
        mov        i,eax;

        test      ecx,ecx;
        jnz        label2;

        mov        eax,sum1;        //sum1/sum2
        mov        ebx,sum2;
        div        bl;
        mov        ah,0;
        mov        re,eax;

    }    
    /*
    half_m_h=(m_h-1)/2;
    half_m_w=(m_w-1)/2;
    sum1=0;
    sum2=0;
    for (i=0;i<m_w*m_h;i++)
    {
        sum2+=m[i];
    }

    for (i=y-half_m_h,ii=0;i<=y+half_m_h;i++,ii++)
    {
        for (j=x-half_m_w,jj=0;j<=x+half_m_w;j++,jj++)
        {
            sum1+=img[i*i_w+j]*m[ii*m_w+jj];
        }
    }
    re=int(sum1/sum2);
    */
    return re;
}

int main()
{
    IplImage *image;
    CvScalar s;
    image=cvLoadImage("C:/Users/tc/Documents/Visual Studio 2010/Projects/vm/Debug/lena.jpg",0);

    int *img;
    img=new int[image->height*image->width];

    for (int i=0;i<image->height;i++)
    {
        for (int j=0;j<image->width;j++)
        {
            s=cvGet2D(image,i,j);
            img[i*image->width+j]=(int)s.val[0];
        }
    }

    int *m;
    m=new int[9];
    for (int i=0;i<9;i++)
    {
        m[i]=1;
    }

    for (int i=1;i<image->height-1;i++)
    {
        for (int j=1;j<image->width-1;j++)
        {
            s=cvGet2D(image,i,j);
            s.val[0]=conv(img,image->height,image->width,m,3,3,i,j);
            cvSet2D(image,i,j,s);
        }
    }

    cvNamedWindow("lena",1);
    cvShowImage("lena",image);

    cvWaitKey(0);
    cvReleaseImage(&image);
    cvDestroyAllWindows();
    delete[] img;
    delete[] m;
    return 0;
}

注:要是使用mmx,sse指令效果就更好了,可惜这个我不太熟悉。
原文地址:https://www.cnblogs.com/tiandsp/p/2793442.html