您好,登錄后才能下訂單哦!
基本原理:
1、最近鄰插值:變換后的目標圖像某點像素值等于源圖像中與變換前相應點最近的點的像素值。具體操作為,設水平方向和垂直方向縮放的比例分別為w和h,那么目標圖像中的點des(x,y)對應的源圖像中的點src的坐標為(x0,y0)=(x/w,y/h)。其中,x0,y0可能為小數,故對其四舍五入,即(x0,y0)=int(x0+0.5,y0+0.5),因此點des(x,y)的像素值就是點src(x0,y0)的像素值。
2、雙線性插值:由1中最近鄰插值中的四舍五入前的點src(x0,y0)得到它的2*2區域4個鄰域像素點的坐標,即(x1,y1)=(int(x0),int(y0)),(x1,y2)=int(x1,y1+1),(x2,y1)=(x1+1,y1),(x2,y2)=(x1+1,y1+1),然后計算權重q1=(x0-x1)*(y0-y1),q2=(1.0-(x0-x1))*(y0-y1),q4=(x0-x1)*(1.0-(y0-y1)),q3=(1.0-(x0-x1))*(1.0-(y0-y1),用value(x,y)表示點(x,y)處的像素值,則目標圖像中的點des(x,y)對應像素值value(x,y)=value(x2,y2)*q1+value(x1,y2)*q2+value(x1,y1)*q3+value(x2,y1)*q4,
c/c++實現及處理效果:
1、最近鄰插值
void GeometryTrans::Zoom(float ratioX, float ratioY) { //釋放舊的輸出圖像緩沖區 if(m_pImgDataOut!=NULL){ delete []m_pImgDataOut; m_pImgDataOut=NULL; } //輸出圖像的寬和高 m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ; m_imgHeightOut=int(m_imgHeight*ratioY+0.5); //輸入圖像每行像素字節數 int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4; //輸出圖像每行像素字節數 int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4; //申請緩沖區,存放輸出結果 m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut]; //每像素字節數,輸入圖像與輸出圖像相同 int pixelByte=m_nBitCount/8; //輸出圖像在輸入圖像中待插值的位置坐標 int coordinateX, coordinateY; //循環變量,輸出圖像的坐標 int i, j; //循環變量,像素的每個通道 int k; //近鄰插值 for(i=0; i< m_imgHeightOut; i++){ for(j=0; j<m_imgWidthOut; j++){ //輸出圖像坐標為(j,i)的像素映射到原圖中的坐標值,即插值位置 coordinateX=j/ratioX+0.5; coordinateY=i/ratioY+0.5; //若插值位置在輸入圖像范圍內,則近鄰插值 if(0<=coordinateX&&coordinateX<m_imgWidth && coordinateY>=0&&coordinateY<m_imgHeight){ for(k=0;k<pixelByte;k++) *(m_pImgDataOut + i * lineByteOut + j*pixelByte + k) =*(m_pImgData+ coordinateY*lineByteIn+ coordinateX*pixelByte + k) ; } else //若不在輸入圖像范圍內,則置255 { for(k=0;k<pixelByte;k++) *(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255; } } } }
2、雙線性插值
void GeometryTrans::Zoom(float ratioX, float ratioY) { //釋放舊的輸出圖像緩沖區 if(m_pImgDataOut!=NULL){ delete []m_pImgDataOut; m_pImgDataOut=NULL; } //輸出圖像的寬和高 m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ; m_imgHeightOut=int(m_imgHeight*ratioY+0.5); //輸入圖像每行像素字節數 int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4; //輸出圖像每行像素字節數 int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4; //申請緩沖區,存放輸出結果 m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut]; //每像素字節數,輸入圖像與輸出圖像相同 int pixelByte=m_nBitCount/8; //輸出圖像在輸入圖像中待插值的位置坐標 float coordinateX, coordinateY; //循環變量,輸出圖像的坐標 int i, j; //循環變量,像素的每個通道 int k; int y1,y2, x1,x2; float fx1,fx2, fy1, fy2; //雙線性插值 for(i=0; i< m_imgHeightOut; i++) { coordinateY = i/ratioY; y1 = (int)coordinateY; if(y1 == m_imgHeightOut-1) y2 = y1; else y2 = y1 + 1; fy1 = coordinateY-y1; fy2 = (float)1.0 - fy1; for(j=0; j<m_imgWidthOut; j++) { coordinateX = j/ratioX; x1 = (int)coordinateX; if(x1 == m_imgWidthOut-1) x2 = x1; else x2 = x1+1; fx1 = coordinateX-x1; fx2 = (float)1.0 - fx1; //所求的源圖像中的2*2區域4個鄰近象素點坐標為(x1, y1) (x1, y2) (x2, y1) (x2,y2) //計算4個權重 float s1 = fx1*fy1; float s2 = fx2*fy1; float s3 = fx2*fy2; float s4 = fx1*fy2; //輸出圖像坐標為(j,i)的像素映射到原圖中的坐標值,即插值位置 //若插值位置在輸入圖像范圍內,則雙線性插值 if(0<=coordinateX&&coordinateX<m_imgWidth && coordinateY>=0&&coordinateY<m_imgHeight) { for(k=0;k<pixelByte;k++) *(m_pImgDataOut + i * lineByteOut + j*pixelByte + k) =(int)((*(m_pImgData+ y2*lineByteIn+ x2*pixelByte + k))*s1+ (*(m_pImgData+ y2*lineByteIn+ x1*pixelByte + k))*s2+ (*(m_pImgData+ y1*lineByteIn+ x1*pixelByte + k))*s3+ (*(m_pImgData+ y1*lineByteIn+ x2*pixelByte + k))*s4); } else //若不在輸入圖像范圍內,則置255 { for(k=0;k<pixelByte;k++) *(m_pImgDataOut + i * lineByteOut + j*pixelByte+k) = 255; } } } }
總結:由處理效果可知,最近鄰插值有鋸齒現象,灰度值不連續,而雙線性插值灰度值連續,圖像比較平滑。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。