圖像處理時用的卷積函數


  做圖像處理,最耗時間的運算應該就是卷積運算那一步了。以后如果有機會在用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指令效果就更好了,可惜這個我不太熟悉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM