解説クラスCopyClear(17)
解説クラスCopyClear(17)
2025年1月22初講(初稿)
この講義は解説『解説クラスCopyClear(16)』
の続きです!
(4-14-43)関数「int RotateImageInterpolate(
TypeArray* ps,TypeArray* pd,
double a,double x1,
double y1,double x2,double y2,
int dataSize){・・・}」
/************************************************************************/
/***** 図形の回転を行うコマンド:実行部:配列版:座標補間版 *****/
/***** ROTATE,a,x1,y1,x2,y2,s,d *****/
/***** ①D配列を基準に回転するため回転角の正負を反転します。 *****/
/***** ②D(x,y)=S(base.x[x]+offset.x[y],base.y[x]+offset.y[y])と*****/
/***** なるような配列 PTR TableとOffset-Tableを作成します。 *****/
/***** makeRotateTable()関数 *****/
/***** ③上記で作成したテーブルを使用してS→Dに転送:rotate()関数*****/
/************************************************************************/
int CopyClear::RotateImageInterpolate(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double a, // 回転角:ラジアン
double x1, // S配列回転中心x
double y1, // S配列回転中心y
double x2, // D配列回転中心x
double y2, // D配列回転中心y
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
TypeXYI* base; // S配列Base-xytbl
TypeXYI* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYI*)malloc( // BaseTableを確保
sizeof(TypeXYI) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYI*)malloc( // OffsetTableを確保
sizeof(TypeXYI) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTable( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteInterpolate( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortInterpolate( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongInterpolate( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatInterpolate( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
☆備考☆この関数はファイル「CopyClear330」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
(A)関数「RotateImageInterpolate()」の【関数名】
「Rotate」は、英単語「Rotate」で回転、ココでは、
画像の二次元表面的な幾何的回転処理です!
「Interpolate」は、英単語「Interpolate」補完するです!
ココでは、整数座標の間を補完する為に画素の値も中間の値
も書き込まれる幾何的変換です!
(B)関数「int RotateImageInterpolate()」の【返値】
この関数内で明示的に検査しているのは、画像情報が、
SD両者共同じ画素単位で無ければ、エラーコード
「STI_FLG」を辺値とし返し関数終了!更に、
仮引数「int dataSize,」が不正ならば、エラーコード
「STI_FLG」を辺値とし返し関数終了!
そして、内部でメモリ取得して居るので取得に失敗時、
エラーコード「STI_MEM」を返し終了!
それ以外は、「return(END_STI);」と正常終了を返しま
す★注意★何故、細かい引数チェックを行わないかは、
処理不能なパラメータの時は、単にサブルーチン関数で処理
シナイだけで終了するからです!
(C)関数「RotateImageInterpolate()」の【仮引数】
int CopyClear::RotateImageInterpolate(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double a, // 回転角:ラジアン
double x1, // S配列回転中心x
double y1, // S配列回転中心y
double x2, // D配列回転中心x
double y2, // D配列回転中心y
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
「TypeArray* ps,」は、S(元)画像情報
「TypeArray* pd,」は、D(結果)画像情報
「double a,」は、回転角度指定★注意★単位は、ラディアン
「double x1,」は、S(元)画像の回転中心X座標
「double y1,」は、S(元)画像の回転中心Y座標
「double x2,」は、D(結果)画像の回転中心X座標
「double y2,」は、D(結果)画像の回転中心Y座標
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
(D)関数「RotateImageInterpolate()」の【アルゴリズム】
){
TypeXYI* base; // S配列Base-xytbl
TypeXYI* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYI*)malloc( // BaseTableを確保
sizeof(TypeXYI) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYI*)malloc( // OffsetTableを確保
sizeof(TypeXYI) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTable( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteInterpolate( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortInterpolate( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongInterpolate( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatInterpolate( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
(D-1)ローカル変数
){
TypeXYI* base; // S配列Base-xytbl
TypeXYI* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
「TypeXYIbase;」は、S画像基底XY座標テーブル
「TypeXYIoffset;」は、S画像変位XY座標テーブル
「int adrS;」は、S(元)実画像機械アドレス
「int adrD;」は、D(結果)実画像機械アドレス★注意★
SD両者共にポインタで無く整数型の「int 」で扱う!
「int hS;」は、水平幅:S画像
「int hD;」は、水平幅:D画像
「int vS;」は、垂直幅:S画像
「int vD;」は、垂直幅:D画像
「int incS;」は、増加幅:S画像
「int incD;」は、増加幅:D画像
(D-2)アルゴリズムコード
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYI*)malloc( // BaseTableを確保
sizeof(TypeXYI) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYI*)malloc( // OffsetTableを確保
sizeof(TypeXYI) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTable( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteInterpolate( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortInterpolate( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongInterpolate( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatInterpolate( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
「if(ps->w!=pd->w){return(STI_FLG);}」は、SD画像の
画素単位が異なればエラーコード「STI_FLG」を辺値とし
返し関数終了!
「if(dataSize<=0){return(STI_FLG);}」は、画素サイズ「dataSize」が0以下の場合、エラーコード「STI_FLG」
を辺値とし返し関数終了!
「if(a==0.0){return(MoveImage(ps,pd,x2-x1,y2-y1,
dataSize,sw));}」は、角度指定≪仮引数「double a,」≫
が、「0.0」の場合、回転では無く幾何移動サブルーチン
関数「MoveImage(ps,pd,x2-x1,y2-y1,dataSize,sw)」で
処理し、その関数の辺値をコノ関数辺値とし関数終了!
「if(sw){return(RotateImageInterpolate(ps,pd,a,
x1,y1,x2,y2,dataSize));}」は、仮引数「int sw」が
真「≠0」≪詰り補正を行う場合≫は、サブルーチン関数
「RotateImageInterpolate(ps,pd,a,x1,y1,x2,y2,
dataSize)」とサブルーチン関数で処理しその関数の辺値を
コノ関数辺値とし関数終了!
「adrS=ps->adr;adrD=pd->adr;」は、実処理ポインタの
値をローカル変数に格納して高速化★注意★整数型の変数
にしているのは、最初に作成したターゲットCPUが、
MC68Kでポインタ変数を数少ないCPUレジスタに割
り当てる時に都合が良く、この変数を各サブルーチン関数
で処理する時に、ソレゾレ((BYTE )adrS)とかと型変換を
明示的に使用して速度ロスを抑えた為です!本当に極僅か
ですが高速化(nsの単位)したのだ!
「hS=ps->h;hD=pd->h;」は、SD両者の水平幅を変数に
格納する事で高速化!
「vS=ps->v;vD=pd->v;」は、SD両者の垂直幅を変数に
格納する事で高速化!
「incS=ps->inc;incD=pd->inc;」は、SD両者の増加幅を
変数に格納する事で高速化!
「base=(TypeXYI)malloc(sizeof(TypeXYI)*(hD+10));」は、
座標変換作業用のテーブル配列をメモリ取得≪型「TypeXYI」は、解説『解説クラスSupport』で解説しているXY座標とインデックスの複合です≫、
C言語システム標準のメモリ取得関数「malloc()」の取得
サイズ「sizeof(TypeXYI)(hD+10)」は、
「sizeof(TypeXYI)」と型「TypeXYI」自体のバイト数と
「(hD+10)」水平幅+α≪ギリギリで無く少し多めに取得
するのは★注意★細かい座標範囲特定の手間を少しでも減
らせる為です!≫
「if(base==0){return(STI_MEM);}」は、メモリ取得に
失敗時にエラーコード「STI_MEM」を辺値で返し関数終了!
「offset=(TypeXYI)malloc(sizeof(TypeXYI)*
(vD+10));」は、座標変換作業用のテーブル配列をメモリ
取得≪型「TypeXYI」は、解説『解説クラスSupport
』で解説しているXY座標とインデックスの複合です≫、
C言語システム標準のメモリ取得関数「malloc()」の取得
サイズ「sizeof(TypeXYI)*(vD+10)」は、「sizeof(TypeXYI)」と型「TypeXYI」自体のバイト数と「(vD+10)」垂直幅+α≪
ギリギリで無く少し多めに取得するのは★注意★細かい座標範囲特定の手間を少しでも減らせる為です!≫
「if(offset==0){return(STI_MEM);}」は、メモリ取得に失敗時にエラーコード「STI_MEM」を辺値で返し関数終了!
「makeRotateTable(-a,x1,y1,x2,y2,base,offset,
hD,vD,dataSize);」は、先ほどメモリ取得した「base」・
「offset」に対してサブルーチン
関数「makeRotateTable()」で幾何変換する座標情報を
算出します!
「if(ps->w==1){rotateByteInterpolate(base,offset,
(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,incS,incD,
dataSize);}」は、選択条件「ps->w==1」で1バイト画素
画像ならば、サブルーチン関数「rotateByteInterpolate(
base,offset,(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,
incS,incD,dataSize);」とサブルーチン
関数「rotateByteInterpolate()」で処理します!
「else if(ps->w==2){rotateShortInterpolate(base,
offset,(short *)adrS,hS,vS,(short *)adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==2」で2バイト
画素画像ならば、サブルーチン
関数「rotateShortInterpolate(base,offset,
(short *)adrS,hS,vS,(short *)adrD,hD,vD,incS,incD,
dataSize);」とサブルーチン関数「rotateShortInterpolate()」で処理します!
「else if(ps->w==4){rotateLongInterpolate(base,
offset,(long )adrS,hS,vS,(long )adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==4」で4バイト
画素(整数型)画像ならば、サブルーチン
関数「rotateLongInterpolate(base,offset,
(long )adrS,hS,vS,(long )adrD,hD,vD,incS,incD,
dataSize);」とサブルーチン
関数「rotateLongInterpolate()」で処理します!
★注意★補正しない関数「RotateImage()」では、4バイト
画素単位ならば整数型も実数型(float単精度浮動小数点型)
も同じサブルーチン関数「rotateLong()」で処理しますが、
補正するので画素の値が補正で変更される為、整数型専用の
サブルーチン関数「rotateLongInterpolate()」を使用します!
「else if(ps->w==101){rotateFloatInterpolate(base,
offset,(float)adrS,hS,vS,(float)adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==101」で
4バイト画素(float単精度浮動小数点型)画像ならば、
サブルーチン関数「rotateFloatInterpolate(base,offset,
(float)adrS,hS,vS,(float)adrD,hD,vD,incS,incD,dataSize);」と
サブルーチン関数「rotateFloatInterpolate()」で処理します!
★注意★補正しない関数「RotateImage()」では、4バイト
画素単位ならば整数型も実数型(float単精度浮動小数点型)
も同じサブルーチン関数「rotateFloat()」で処理しますが、
補正するので画素の値が補正で変更される為、実数型専用の
サブルーチン関数「rotateFloatInterpolate()」を使用
します!
★備考★画素単位の選択肢「ps->w==102」と8バイト
倍精度浮動小数点型は用意しませんでした!ライブラリ作成
当時、需要が無いと判断したのですが!ソースコードで公開
していますので必要な方は、このソースコードを参考にして
追加して下さい!私(作者)は、新規に作成したコード動作
保証はできませんので悪しからず!
「free(base);free(offset);」は、メモリ取得した後始末!
「return(END_STI);」は、正常終了を返し関数終了!
(E)関数「RotateImageInterpolate()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
(4-14-44)関数「int RotateImageReal(
TypeArray* ps,TypeArray*pd,
double a,double x1,
double y1,double x2,double y2,
int dataSize=1){・・・}」
/************************************************************************/
/***** 図形の回転を行うコマンド:実行部:配列版:座標補間版 *****/
/***** ROTATE,a,x1,y1,x2,y2,s,d *****/
/***** ①D配列を基準に回転するため回転角の正負を反転します。 *****/
/***** ②D(x,y)=S(base.x[x]+offset.x[y],base.y[x]+offset.y[y])と*****/
/***** なるような配列 PTR TableとOffset-Tableを作成します。 *****/
/***** makeRotateTable()関数 *****/
/***** ③上記で作成したテーブルを使用してS→Dに転送:rotate()関数*****/
/************************************************************************/
int CopyClear::RotateImageReal(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double a, // 回転角:ラジアン
double x1, // S配列回転中心x
double y1, // S配列回転中心y
double x2, // D配列回転中心x
double y2, // D配列回転中心y
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
TypeXYD* base; // S配列Base-xytbl
TypeXYD* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYD*)malloc( // BaseTableを確保
sizeof(TypeXYD) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYD*)malloc( // OffsetTableを確保
sizeof(TypeXYD) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTableReal( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteReal( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortReal( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongReal( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatReal( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
☆備考☆この関数はファイル「CopyClear340」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
(A)関数「RotateImageReal()」の【関数名】
「Real」は、実数型を意味します!何故、
ワザワザ「実数型」と名称を付けたかと説明します!
前に解説した関数「RotateImageInterpolate()」と
補間する関数でも基本、高速化処理として下駄履した
整数型の演算で行っているのだが、この関数では、最新の
CPUではCPU自体の浮動小数演算が高速化されて居る
ので座標変換や画素の補間に実数型(浮動小数演算)を多用
した事を示す為に付けた名称です!
★注意★安価だが、実数型(浮動小数演算)が遅いCPU
では、使用シナイ方が得策でしょう!
(B)関数「int RotateImageReal()」の【返値】
この関数内で明示的に検査しているのは、画像情報が、
SD両者共同じ画素単位で無ければ、エラーコード
「STI_FLG」を辺値とし返し関数終了!更に、
仮引数「int dataSize,」が不正ならば、エラーコード
「STI_FLG」を辺値とし返し関数終了!
そして、内部でメモリ取得して居るので取得に失敗時、
エラーコード「STI_MEM」を返し終了!
それ以外は、「return(END_STI);」と正常終了を返しま
す★注意★何故、細かい引数チェックを行わないかは、
処理不能なパラメータの時は、単にサブルーチン関数で処理
シナイだけで終了するからです!
(C)関数「RotateImageReal()」の【仮引数】
int CopyClear::RotateImageReal(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double a, // 回転角:ラジアン
double x1, // S配列回転中心x
double y1, // S配列回転中心y
double x2, // D配列回転中心x
double y2, // D配列回転中心y
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
「TypeArray* ps,」は、S(元)画像情報
「TypeArray* pd,」は、D(結果)画像情報
「double a,」は、回転角度指定★注意★単位は、ラディアン
「double x1,」は、S(元)画像の回転中心X座標
「double y1,」は、S(元)画像の回転中心Y座標
「double x2,」は、D(結果)画像の回転中心X座標
「double y2,」は、D(結果)画像の回転中心Y座標
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
(D)関数「RotateImageReal()」の【アルゴリズム】
){
TypeXYD* base; // S配列Base-xytbl
TypeXYD* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYD*)malloc( // BaseTableを確保
sizeof(TypeXYD) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYD*)malloc( // OffsetTableを確保
sizeof(TypeXYD) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTableReal( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteReal( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortReal( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongReal( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatReal( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
(D-1)ローカル変数
){
TypeXYD* base; // S配列Base-xytbl
TypeXYD* offset; // S配列Offsetxytbl
int adrS; // アドレス:S
int adrD; // アドレス:D
int hS; // 水平幅:S
int hD; // 水平幅:D
int vS; // 垂直幅:S
int vD; // 垂直幅:D
int incS; // 増加幅:S
int incD; // 増加幅:D
「TypeXYD* base;」は、S画像基底XY座標テーブル
「TypeXYD* offset;」は、S画像変位XY座標テーブル
★注意★型名「TypeXYD」は、
解説『解説クラスSupport』に記載して居る
【(2-1)座標組用データ構造】で説明!
「int adrS;」は、S(元)実画像機械アドレス
「int adrD;」は、D(結果)実画像機械アドレス★注意★
SD両者共にポインタで無く整数型の「int 」で扱う!
「int hS;」は、水平幅:S画像
「int hD;」は、水平幅:D画像
「int vS;」は、垂直幅:S画像
「int vD;」は、垂直幅:D画像
「int incS;」は、増加幅:S画像
「int incD;」は、増加幅:D画像
(D-2)アルゴリズムコード
if( ps->w != pd->w ){ // 画素処理単位が
return( STI_FLG ); // 異なれば不正を返す
} //
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( a == 0.0 ){ // 回転角=0の場合
return( MoveImage( ps, pd, x2 - x1, y2 - y1, // 左記で画像移動
dataSize, TRUE ) ); // (補間付き)
} //
adrS = ps->adr; // S・Dの実処理
adrD = pd->adr; // ADR を取り出し
hS = ps->h; // S・Dの
hD = pd->h; // 水平幅取り出し
vS = ps->v; // S・Dの
vD = pd->v; // 垂直幅取り出し
incS = ps->inc; // S・Dの増加幅
incD = pd->inc; // を取り出し
base = (TypeXYD*)malloc( // BaseTableを確保
sizeof(TypeXYD) * ( hD + 10 ) ); // (水平幅+α)
if( base == 0 ){ // 確保失敗時は
return( STI_MEM ); // 左記を返す
} //
offset = (TypeXYD*)malloc( // OffsetTableを確保
sizeof(TypeXYD) * ( vD + 10 ) ); // (垂直幅+α)
if( offset == 0 ){ // 確保失敗時は
free( base ); // メモリ解放:BaseTable
return( STI_MEM ); // 左記を返す
} //
makeRotateTableReal( -a, x1, y1, x2, y2, base, offset, // 回転座標のTableを
hD, vD, dataSize ); // 作成する
if( ps->w == 1 ){ // 8ビット版なら
rotateByteReal( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShortReal( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 ){ // 32ビット版なら
rotateLongReal( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 101 ){ // 単精度版なら
rotateFloatReal( base, offset, // 左記で回転実行
(float*)adrS, hS, vS, //
(float*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
「if(ps->w!=pd->w){return(STI_FLG);}」は、SD画像の
画素単位が異なればエラーコード「STI_FLG」を辺値とし
返し関数終了!
「if(dataSize<=0){return(STI_FLG);}」は、画素サイズ「dataSize」が0以下の場合、エラーコード「STI_FLG」
を辺値とし返し関数終了!
「if(a==0.0){return(MoveImage(ps,pd,x2-x1,y2-y1,
dataSize,TRUE));}」は、角度指定≪仮引数「double a,」≫
が、「0.0」の場合、回転では無く幾何移動サブルーチン
関数「MoveImage(ps,pd,x2-x1,y2-y1,dataSize,TRUE)」で
処理し、その関数の辺値をコノ関数辺値とし関数終了!
「adrS=ps->adr;adrD=pd->adr;」は、実処理ポインタの
値をローカル変数に格納して高速化★注意★整数型の変数
にしているのは、最初に作成したターゲットCPUが、
MC68Kでポインタ変数を数少ないCPUレジスタに割
り当てる時に都合が良く、この変数を各サブルーチン関数
で処理する時に、ソレゾレ((BYTE )adrS)とかと型変換を
明示的に使用して速度ロスを抑えた為です!本当に極僅か
ですが高速化(nsの単位)したのだ!
「hS=ps->h;hD=pd->h;」は、SD両者の水平幅を変数に
格納する事で高速化!
「vS=ps->v;vD=pd->v;」は、SD両者の垂直幅を変数に
格納する事で高速化!
「incS=ps->inc;incD=pd->inc;」は、SD両者の増加幅を
変数に格納する事で高速化!
「base=(TypeXY D)malloc(sizeof(TypeXY D)*(hD+10));」は、座標変換作業用のテーブル配列をメモリ取得≪★注意★
型名「TypeXY D」は、解説『解説クラスSupport』に記載して居る【(2-1)座標組用データ構造】で説明!≫、
C言語システム標準のメモリ取得関数「malloc()」の取得
サイズ「sizeof(TypeXY D)(hD+10)」は、「sizeof(TypeXY D)」と型「TypeXY D」自体のバイト数と「(hD+10)」水平幅+α≪ギリギリで無く少し多めに取得するのは★注意★細かい座標範囲特定の手間を少しでも減らせる為です!≫
「if(base==0){return(STI_MEM);}」は、メモリ取得に
失敗時にエラーコード「STI_MEM」を辺値で返し関数終了!
「offset=(TypeXY D)malloc(sizeof(TypeXY D)*
(vD+10));」は、座標変換作業用のテーブル配列をメモリ
取得≪★注意★型名「TypeXY D」は、
解説『解説クラスSupport』に記載して居る
【(2-1)座標組用データ構造】で説明!≫、
C言語システム標準のメモリ取得関数「malloc()」の取得
サイズ「sizeof(TypeXY D)*(vD+10)」は、
「sizeof(TypeXY D)」と型「TypeXY D」自体のバイト数と
「(vD+10)」垂直幅+α≪ギリギリで無く少し多めに取得
するのは★注意★細かい座標範囲特定の手間を少しでも減
らせる為です!≫
「if(offset==0){return(STI_MEM);}」は、メモリ取得に
失敗時にエラーコード「STI_MEM」を辺値で返し関数終了!
「makeRotateTableReal(-a,x1,y1,x2,y2,base,offset,
hD,vD,dataSize);」は、先ほどメモリ取得した「base」・
「offset」に対してサブルーチン関数「makeRotateTableReal()」で幾何変換する座標情報を算出
します!★注意★このサブルーチン関数
「makeRotateTableReal()」を使用するのでコノ関数自体が
「Real」を名称として使用した理由です!
「if(ps->w==1){rotateBYTE Real(base,offset,
(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,incS,incD,
dataSize);}」は、選択条件「ps->w==1」で1バイト画素
画像ならば、サブルーチン関数「rotateBYTE Real(
base,offset,(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,
incS,incD,dataSize);」とサブルーチン
関数「rotateBYTE Real()」で処理します!
「else if(ps->w==2){rotateShortReal(base,
offset,(short *)adrS,hS,vS,(short *)adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==2」で2バイト
画素画像ならば、サブルーチン関数「rotateShortReal(base,offset,(short *)adrS,hS,vS,
(short *)adrD,hD,vD,incS,incD,dataSize);」とサブルーチン
関数「rotateShortReal()」で処理します!
「else if(ps->w==4){rotateLong Real(base,
offset,(long )adrS,hS,vS,(long )adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==4」で4バイト
画素(整数型)画像ならば、サブルーチン
関数「rotateLong Real(base,offset,
(long )adrS,hS,vS,(long )adrD,hD,vD,incS,incD,
dataSize);」とサブルーチン
関数「rotateLong Real()」で処理します!
「else if(ps->w==101){rotateFloatReal(base,
offset,(float)adrS,hS,vS,(float)adrD,hD,vD,incS,
incD,dataSize);}」は、選択条件「ps->w==101」で
4バイト画素(float単精度浮動小数点型)画像ならば、
サブルーチン関数「rotateFloatReal(base,offset,
(float)adrS,hS,vS,(float)adrD,hD,vD,incS,incD,
dataSize);」とサブルーチン
関数「rotateFloatReal()」で処理します!
★備考★画素単位の選択肢「ps->w==102」と8バイト
倍精度浮動小数点型は用意しませんでした!ライブラリ作成
当時、需要が無いと判断したのですが!ソースコードで公開
していますので必要な方は、このソースコードを参考にして
追加して下さい!私(作者)は、新規に作成したコード動作
保証はできませんので悪しからず!
「free(base);free(offset);」は、メモリ取得した後始末!
「return(END_STI);」は、正常終了を返し関数終了!
(E)関数「RotateImageReal()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
本日(1月22)の講義はココまでとします!
流石に新しくと言うか「画像幾何変換」の話に遷ったの
で受講者の皆様が消化出来る為にココまでとします!
十分にNoteサーバーが動く分量なので続きは、
この文章に引き続き掲載しますので御贔屓をお願いします!
と何時もなら記載するのですが、ここで、この解説文章
『解説クラスCopyClear(17)』は終了します!
先ず、編集するのに動きが重たい、そして次から、
【ソーティング】系の関数の解説に成るので新しく
新規解説『解説クラスCopyClear(18)』として
近々、始めますので宜しく、御贔屓の程、お願いします!