圖形影象處理-之-彩色轉化到灰度的速度優化
圖形影象處理-之-彩色轉化到灰度的速度優化
HouSisong@GMail.com 2009.02.08
tag:灰度演算法,速度優化,定點數優化,MMX,SSE,SSE2,CPU快取優化
摘要:
彩色轉化到灰度的速度優化文章包括圖形影象處理簡單Demo框架和灰度轉換的實
現及其速度優化,並演示其使用SIMD指令集的優化;
本篇文章將第一次提供完整的可以編譯的影象處理完整專案程式碼;
(以後會用這個框架逐步改寫以前的圖形影象處理文章)
正文:
為了便於討論,這裡只處理32bit的ARGB顏色;程式碼使用C++;使用的編譯器為vc2008;
(經過測試程式碼也可以在DevC++和xcode下編譯通過) 測試使用的CPU為AMD64x2 4200+(2.33G);
速度測試說明:
只測試記憶體資料到記憶體資料的ARGB32顏色的灰度轉化;
測試圖片是800*600; fps表示每秒鐘的幀數,值越大表示函式越快;
A: 圖形影象處理簡單Demo框架
我以前寫的圖形影象處理方面的blog文章都沒有完整的可以編譯執行的程式碼,
而僅僅列出了關鍵的核心程式碼;經常有網友看了我的文章,但因為不能實際執行看看,
從而對程式碼的理解不深,也不能把程式碼移植到自己的專案中使用; 所以決定為我的圖形
影象處理系列blog文章建立一個簡單的小型的框架;我把它命名為hGraphic32,
它會盡量的小,演示為主,僅支援ARGB32顏色,能夠載入和儲存bmp圖片檔案,能夠在
多個編譯器和平臺下編譯和執行;
現在就下載完整專案原始碼吧: 完整專案原始碼
<hGraphic32>資料夾裡的檔案說明:
"hColor32.h" : 裡面定義了32bitARGB顏色型別Color32,它佔用4位元組,代表一個顏色;
TPixels32Ref是影象資料區的描述資訊,可以把它理解為一個"指標",指向了Color32構成的畫素區;
IPixels32Buf是影象資料區介面,用於描述一個影象的緩衝區;
"hPixels32.h" : 裡面定義了TPixels32類,它實現了IPixels32Buf介面,用於申請和管理一塊記憶體畫素;
"hStream.h" : 裡面定義了IInputStream輸入流介面;
IBufInputStream資料區輸入流介面,繼承自IInputStream;
TFileInputStream檔案輸入流類,它實現了IBufInputStream介面;
IOutputStream輸出流介面;
TFileOutputStream檔案輸出流類,它實現了IOutputStream介面;
"hBmpFile.h" : 裡面定義了TBmpFile類,它負責載入bmp和儲存bmp;
"hGraphic32.h" 檔案include了上面的*.h標頭檔案,所以使用的時候,只要#include "hGraphic32.h"就可以了
B: 灰度轉化專案
所有的轉換和測試程式碼都在"ColorToGray/ColorToGray.cpp"檔案中(帶有main函式的命令列程式);
"ColorToGray/win_vc/ColorToGray.sln"是windows系統下的vc2008專案檔案(測試的時請設定除錯執行目錄為"..");
"ColorToGray/win_DevC++/ColorToGray.dev"是windows系統下的DevC++專案檔案;
"ColorToGray/macosx_xcode/ColorToGray.xcodeproj"是macosx系統下的xcode專案檔案;
你也可以自己建立專案,包含ColorToGray.cpp檔案和<hGraphic32>資料夾下的所有檔案,就可以編譯了;
C: 灰度轉化公式和程式碼實現
文章中用的灰度公式: Gray = R*0.299 + G*0.587 + B*0.114;
程式碼實現:
- //灰度轉換系數
- const double gray_r_coeff=0.299;
- const double gray_g_coeff=0.587;
- const double gray_b_coeff=0.114;
- //處理一個點
- must_inline double toGray_float(const Color32& src){
- return (src.r*gray_r_coeff +src.g*gray_g_coeff +src.b*gray_b_coeff);
- }
- //處理一行
- void colorToGrayLine_float(const Color32* src,Color32* dst,long width){
- for (long x = 0; x < width; ++x){
- int gray=(int)toGray_float(src[x]);
- dst[x]=Color32(gray,gray,gray,src[x].a);//R,G,B都設定為相同的亮度值,A不變
- }
- }
- void colorToGray_float(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_float(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_float 145.49 FPS
////////////////////////////////////////////////////////////////////////////////
D: 將浮點運算轉化為定點數(整數)運算
- must_inline int toGray_int16(const Color32& src){
- const long bit=16;
- const int gray_r_coeff_int=(int)( gray_r_coeff*(1<<bit)+0.4999999 );
- const int gray_g_coeff_int=(int)( gray_g_coeff*(1<<bit)+0.4999999 );
- const int gray_b_coeff_int=(1<<bit)-gray_r_coeff_int-gray_g_coeff_int;
- return (src.r*gray_r_coeff_int +src.g*gray_g_coeff_int +src.b*gray_b_coeff_int) >> bit;
- }
- inline void colorToGrayLine_int16(const Color32* src,Color32* dst,long width){
- for (long x = 0; x < width; ++x){
- int gray=toGray_int16(src[x]);
- dst[x]=Color32(gray,gray,gray,src[x].a);
- }
- }
- colorToGray_int16(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_int16(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_int16 355.33 FPS
////////////////////////////////////////////////////////////////////////////////
E: 做一個簡單的迴圈程式碼展開
- //四路展開
- void colorToGrayLine_int16_expand4(const Color32* src,Color32* dst,long width){
- long widthFast=width>>2<<2;
- for (long x = 0; x < widthFast; x+=4){
- int gray0=toGray_int16(src[x ]);
- int gray1=toGray_int16(src[x+1]);
- dst[x ]=Color32(gray0,gray0,gray0,src[x ].a);
- dst[x+1]=Color32(gray1,gray1,gray1,src[x+1].a);
- int gray2=toGray_int16(src[x+2]);
- int gray3=toGray_int16(src[x+3]);
- dst[x+2]=Color32(gray2,gray2,gray2,src[x+2].a);
- dst[x+3]=Color32(gray3,gray3,gray3,src[x+3].a);
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- colorToGray_int16_expand4(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_int16_expand4(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_int16_expand4 413.22 FPS
////////////////////////////////////////////////////////////////////////////////
F: 一個特別的版本
在高階語言範圍內進行單條指令多資料流計算,減少需要的乘法量;
在乘法運算代價比較高昂的cpu上應該效果不錯; (x86上速度可能慢)
- must_inline UInt32 toGray_int8_opMul(const Color32* src2Color){
- const UInt32 gray_r_coeff_8=(UInt32)( gray_r_coeff*(1<<8)+0.4999999);
- const UInt32 gray_g_coeff_8=(UInt32)( gray_g_coeff*(1<<8)+0.4999999);
- const UInt32 gray_b_coeff_8=(1<<8)-gray_r_coeff_8-gray_g_coeff_8;
- UInt32 RR,GG,BB;
- BB=src2Color[0].b | (src2Color[1].b<<16);
- GG=src2Color[0].g | (src2Color[1].g<<16);
- RR=src2Color[0].r | (src2Color[1].r<<16);
- BB*=gray_b_coeff_8;
- GG*=gray_g_coeff_8;
- RR*=gray_r_coeff_8;
- return BB+GG+RR;
- }
- void colorToGrayLine_int8_opMul(const Color32* src,Color32* dst,long width){
- long widthFast=width>>2<<2;
- for (long x = 0; x < widthFast; x+=4){
- UInt32 gray01=toGray_int8_opMul(&src[x ]);
- int gray0=(gray01&0x0000FF00)>>8;
- int gray1=gray01>>24;
- dst[x ]=Color32(gray0,gray0,gray0,src[x ].a);
- dst[x+1]=Color32(gray1,gray1,gray1,src[x+1].a);
- UInt32 gray23=toGray_int8_opMul(&src[x+2]);
- int gray2=(gray23&0x0000FF00)>>8;
- int gray3=gray23>>24;
- dst[x+2]=Color32(gray2,gray2,gray2,src[x+2].a);
- dst[x+3]=Color32(gray3,gray3,gray3,src[x+3].a);
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- colorToGray_int8_opMul(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_int8_opMul(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_int8_opMul 387.97 FPS
////////////////////////////////////////////////////////////////////////////////
G: 內聯彙編的MMX實現版本
注意:這裡的MMX程式碼都只支援x86CPU(奔騰MMX以上CPU);
在x64下不再有MMX暫存器,而應該使用SEE的XMM暫存器;
而且在x64模式下vc2008編譯器還沒有提供內聯彙編的直接支援,而必須使用函式指令方式的實現;
GCC編譯器也支援內聯彙編模式,但是彙編語法不同,請參考相應的說明;
- void colorToGrayLine_MMX(const Color32* src,Color32* dst,long width){
- //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;
- // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]
- const UInt64 csMMX_rgb_coeff_w = (((UInt64)0x00000026)<<32) | 0x004b000f;
- long widthFast=width>>1<<1;
- if (widthFast>0){
- asm{
- pcmpeqb mm5,mm5 // FF FF FF FF FF FF FF FF
- mov ecx,widthFast
- pxor mm7,mm7 // 00 00 00 00 00 00 00 00
- pcmpeqb mm4,mm4 // FF FF FF FF FF FF FF FF
- mov eax,src
- mov edx,dst
- movq mm6,csMMX_rgb_coeff_w
- psrlw mm5,15 // 1 1 1 1
- lea eax,[eax+ecx*4]
- lea edx,[edx+ecx*4]
- pslld mm4,24 // FF 00 00 00 FF 00 00 00
- neg ecx
- loop_beign:
- movq mm0,[eax+ecx*4] // A1 R1 G1 B1 A0 R0 G0 B0
- movq mm1,mm0
- movq mm3,mm0
- punpcklbw mm0,mm7 // 00 A0 00 R0 00 G0 00 B0
- punpckhbw mm1,mm7 // 00 A1 00 R1 00 G1 00 B1
- pmaddwd mm0,mm6 // R0*r_coeff G0*g_coeff+B0*b_coeff
- pmaddwd mm1,mm6 // R1*r_coeff G1*g_coeff+B1*b_coeff
- pand mm3,mm4 // A1 00 00 00 A0 00 00 00
- packssdw mm0,mm1 // sR1 sG1+sB1 sR0 sG0+sB0
- pmaddwd mm0,mm5 // sR1+sG1+sB1 sR0+sG0+sB0
- psrld mm0,7 // 00 00 00 Gray1 00 00 00 Gray0
- movq mm1,mm0
- movq mm2,mm0
- pslld mm1,8 // 00 00 Gray1 00 00 00 Gray0 00
- por mm0,mm3
- pslld mm2,16 // 00 Gray1 00 00 00 Gray0 00 00
- por mm0,mm1
- por mm0,mm2 // A1 Gray1 Gray1 Gray1 A0 Gray0 Gray0 Gray0
- movq [edx+ecx*4],mm0
- add ecx,2
- jnz loop_beign
- }
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- void colorToGray_MMX(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_MMX(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
- asm{
- emms //MMX使用結束
- }
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_MMX 590.84 FPS
////////////////////////////////////////////////////////////////////////////////
H: 優化寫緩衝的內聯彙編的MMX實現版本
該版本相應於上面的MMX版本只改寫了兩句:
一是寫記憶體的movq [edx+ecx*4],mm0 改成了 movntq [edx+ecx*4],mm0 繞過快取
二是函式結束的時候呼叫sfence重新整理寫入
完整程式碼如下:
- void colorToGrayLine_MMX2(const Color32* src,Color32* dst,long width){
- //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;
- // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]
- const UInt64 csMMX_rgb_coeff_w = (((UInt64)0x00000026)<<32) | 0x004b000f;
- long widthFast=width>>1<<1;
- if (widthFast>0){
- asm{
- pcmpeqb mm5,mm5 // FF FF FF FF FF FF FF FF
- mov ecx,widthFast
- pxor mm7,mm7 // 00 00 00 00 00 00 00 00
- pcmpeqb mm4,mm4 // FF FF FF FF FF FF FF FF
- mov eax,src
- mov edx,dst
- movq mm6,csMMX_rgb_coeff_w
- psrlw mm5,15 // 1 1 1 1
- lea eax,[eax+ecx*4]
- lea edx,[edx+ecx*4]
- pslld mm4,24 // FF 00 00 00 FF 00 00 00
- neg ecx
- loop_beign:
- movq mm0,[eax+ecx*4] // A1 R1 G1 B1 A0 R0 G0 B0
- movq mm1,mm0
- movq mm3,mm0
- punpcklbw mm0,mm7 // 00 A0 00 R0 00 G0 00 B0
- punpckhbw mm1,mm7 // 00 A1 00 R1 00 G1 00 B1
- pmaddwd mm0,mm6 // R0*r_coeff G0*g_coeff+B0*b_coeff
- pmaddwd mm1,mm6 // R1*r_coeff G1*g_coeff+B1*b_coeff
- pand mm3,mm4 // A1 00 00 00 A0 00 00 00
- packssdw mm0,mm1 // sR1 sG1+sB1 sR0 sG0+sB0
- pmaddwd mm0,mm5 // sR1+sG1+sB1 sR0+sG0+sB0
- psrld mm0,7 // 00 00 00 Gray1 00 00 00 Gray0
- movq mm1,mm0
- movq mm2,mm0
- pslld mm1,8 // 00 00 Gray1 00 00 00 Gray0 00
- por mm0,mm3
- pslld mm2,16 // 00 Gray1 00 00 00 Gray0 00 00
- por mm0,mm1
- por mm0,mm2 // A1 Gray1 Gray1 Gray1 A0 Gray0 Gray0 Gray0
- movntq [edx+ecx*4],mm0 //和colorToGrayLine_MMX的不同之處
- add ecx,2
- jnz loop_beign
- }
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- colorToGray_MMX2(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_MMX2(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
- asm{
- sfence //重新整理寫入
- emms
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_MMX2 679.50 FPS
////////////////////////////////////////////////////////////////////////////////
I: 使用MMX函式指令方式的實現
MMX/SSE等特殊指令除了內聯彙編來使用外,也可以使用函式指令方式的實現,從而在多種
編譯器下都可以使用SIMD相關指令,可移植性也會好很多;
但現在看來,vc對此的優化還不夠,還可能遇到編譯器的實現bug;
(可以考慮使用intel的編譯器編譯這些程式碼,感覺優化能力很不錯)
- #include <mmintrin.h> //mmx
- //#include <mm3dnow.h> //3dnow
- #include <xmmintrin.h> //sse
- //#include <emmintrin.h> //sse2
- //#include <pmmintrin.h> //sse3
- //#include <tmmintrin.h> //ssse3
- //#include <intrin.h> //sse4a
- //#include <smmintrin.h> //sse4.1
- //#include <nmmintrin.h> //sse4.2
- //----------------------------------
- void colorToGrayLine_MMX_mmh(const Color32* src,Color32* dst,long width){
- //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;
- // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]
- long widthFast=width>>1<<1;
- if (widthFast>0){
- const UInt64 csMMX_rgb_coeff_w =(((UInt64)0x00000026)<<32) | 0x004b000f;
- const __m64 mm6=*(const __m64*)&csMMX_rgb_coeff_w;
- const __m64 mm7=_mm_setzero_si64(); //mm?變數值同colorToGrayLine_MMX中的mmx值一致
- __m64 mm5=_mm_cmpeq_pi8(mm7,mm7); //想寫成__m64 mm5; mm5=_mm_cmpeq_pi8(mm5,mm5);但會出錯:(
- const __m64 mm4=_mm_slli_pi32(mm5,24); // ...
- mm5=_mm_srli_pi16(mm5,15); // ...
- for (long x = 0; x < widthFast; x+=2){
- __m64 mm0=*(__m64*)&src[x];
- __m64 mm1=mm0;
- __m64 mm3=mm0;
- mm0=_mm_unpacklo_pi8(mm0,mm7);
- mm1=_mm_unpackhi_pi8(mm1,mm7);
- mm0=_mm_madd_pi16(mm0,mm6);
- mm1=_mm_madd_pi16(mm1,mm6);
- mm3=_mm_and_si64(mm3,mm4);
- mm0=_mm_packs_pi32(mm0,mm1);
- mm0=_mm_madd_pi16(mm0,mm5);
- mm0=_mm_srli_pi32(mm0,7);
- mm1=mm0;
- __m64 mm2=mm0;
- mm1=_mm_slli_pi32(mm1,8);
- mm0=_mm_or_si64(mm0,mm3);
- mm2=_mm_slli_pi32(mm2,16);
- mm0=_mm_or_si64(mm0,mm1);
- mm0=_mm_or_si64(mm0,mm2);
- *(__m64*)&dst[x]=mm0;
- }
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- void colorToGray_MMX_mmh(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_MMX_mmh(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
- _mm_empty(); //MMX使用結束
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_MMX_mmh 508.69 FPS
////////////////////////////////////////////////////////////////////////////////
優化寫緩衝的使用MMX函式指令方式的實現
- void colorToGrayLine_MMX2_mmh(const Color32* src,Color32* dst,long width){
- //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );
- //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;
- // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]
- long widthFast=width>>1<<1;
- if (widthFast>0){
- const UInt64 csMMX_rgb_coeff_w =(((UInt64)0x00000026)<<32) | 0x004b000f;
- const __m64 mm6=*(const __m64*)&csMMX_rgb_coeff_w;
- const __m64 mm7=_mm_setzero_si64(); //mm?變數值同colorToGrayLine_MMX中的mmx值一致
- __m64 mm5=_mm_cmpeq_pi8(mm7,mm7); // ...
- const __m64 mm4=_mm_slli_pi32(mm5,24); // ...
- mm5=_mm_srli_pi16(mm5,15); // ...
- for (long x = 0; x < widthFast; x+=2){
- __m64 mm0=*(__m64*)&src[x];
- __m64 mm1=mm0;
- __m64 mm3=mm0;
- mm0=_mm_unpacklo_pi8(mm0,mm7);
- mm1=_mm_unpackhi_pi8(mm1,mm7);
- mm0=_mm_madd_pi16(mm0,mm6);
- mm1=_mm_madd_pi16(mm1,mm6);
- mm3=_mm_and_si64(mm3,mm4);
- mm0=_mm_packs_pi32(mm0,mm1);
- mm0=_mm_madd_pi16(mm0,mm5);
- mm0=_mm_srli_pi32(mm0,7);
- mm1=mm0;
- __m64 mm2=mm0;
- mm1=_mm_slli_pi32(mm1,8);
- mm0=_mm_or_si64(mm0,mm3);
- mm2=_mm_slli_pi32(mm2,16);
- mm0=_mm_or_si64(mm0,mm1);
- mm0=_mm_or_si64(mm0,mm2);
- //*(__m64*)&dst[x]=mm0;
- _mm_stream_pi((__m64*)&dst[x],mm0);
- }
- }
- //border
- if (width>widthFast)
- colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);
- }
- void colorToGray_MMX2_mmh(const TPixels32Ref& src,const TPixels32Ref& dst){
- long width=std::min(src.width,dst.width);
- long height=std::min(src.height,dst.height);
- Color32* srcLine=src.pdata;
- Color32* dstLine=dst.pdata;
- for (long y = 0; y < height; ++y){
- colorToGrayLine_MMX2_mmh(srcLine,dstLine,width);
- src.nextLine(srcLine);
- dst.nextLine(dstLine);
- }
- _mm_sfence();//重新整理寫入
- _mm_empty(); //MMX使用結束
- }
////////////////////////////////////////////////////////////////////////////////
//速度測試
//==============================================================================
// colorToGray_MMX2_mmh 540.78 FPS
////////////////////////////////////////////////////////////////////////////////
J:把測試成績放在一起:
////////////////////////////////////////////////////////////////////////////////
//CPU: AMD64x2 4200+(2.33G) 800*600 to 800*600
//==============================================================================
// colorToGray_float 145.49 FPS
// colorToGray_int16 355.33 FPS
// colorToGray_int16_expand4 413.22 FPS
// colorToGray_int8_opMul 387.97 FPS
// colorToGray_MMX 590.84 FPS
// colorToGray_MMX2 679.50 FPS
// colorToGray_MMX_mmh 508.69 FPS
// colorToGray_MMX2_mmh 540.78 FPS
////////////////////////////////////////////////////////////////////////////////
ps:用SSE的浮點指令的版本/用SSE2整數指令的版本/利用SSE3的水平加指令等的實現版本有機會時再補充
ps:SIMD特殊指令集的使用框架請參見我的<YUV視訊格式到RGB32格式轉換的速度優化 中篇>一文,從而
根據CPU對指令集的支援情況動態的呼叫最優的實現函式版本;
相關文章
- Python-OpenCV 處理影象(七):影象灰度化處理PythonOpenCV
- 【數字影象處理】五.MFC影象點運算之灰度線性變化、灰度非線性變化、閾值化和均衡化處理詳解
- 將彩色圖轉化為灰度圖及其原理介紹
- 圖形影象處理-之-高質量的快速的影象縮放 上篇 近鄰取樣插值和其速度優化優化
- matlab中將RGB影象轉化為灰度影象Matlab
- 影象邊緣檢測—sobel運算元(灰度影象,彩色影象)
- Android影像灰度化、線性灰度變化、二值化處理方法Android
- Python-OpenCV 處理影象(八):影象二值化處理PythonOpenCV
- 如何處理 Web 圖片優化?Web優化
- Mysql優化系列之——優化器對子查詢的處理MySql優化
- 如何將真彩色圖轉換為各種灰度圖
- Java將彩色PDF轉為灰度Java
- iOS 圖形效能優化iOS優化
- [Python影象處理] 十一.灰度直方圖概念及OpenCV繪製直方圖Python直方圖OpenCV
- [Python影象處理] 七.影象閾值化處理及演算法對比Python演算法
- CSS把彩色圖片變為灰度圖片CSS
- 【數字影象處理】四.MFC對話方塊繪製灰度直方圖直方圖
- CUDA程式優化心得之錯誤處理優化
- 資料庫優化之表碎片處理資料庫優化
- python將矩陣轉化為灰度圖Python矩陣
- web前端優化之圖片優化Web前端優化
- Web效能優化之圖片優化Web優化
- python - 圖片灰度化、二值化Python
- Swift-影象的效能優化Swift優化
- mysql處理海量資料時的一些優化查詢速度方法MySql優化
- [Python影象處理] 六.影象縮放、影象旋轉、影象翻轉與影象平移Python
- 【數字影象處理】三.MFC實現影象灰度、取樣和量化功能詳解
- 譯文:影象優化(上)優化
- 淺談 Web 影象優化Web優化
- Redo Gap 處理與優化優化
- 影像演算法之直方圖均衡化(灰度影像)演算法直方圖
- 網站優化之路—圖片優化,圖片從模糊到清晰網站優化
- 介面自動化測試-apiAutoTest 優化之資料依賴處理API優化
- Android 之 GPU過度繪製與圖形渲染優化AndroidGPU優化
- 24位真彩色轉換為8位灰度圖片(完整程式碼)
- 遊戲開發新手入門之點陣圖化圖形(轉)遊戲開發
- Unity官方文件之“圖形效能優化-幀偵錯程式”的翻譯Unity優化
- 圖形學之紋理後續/WebGL多紋理處理Web