解説クラスCopyClear(16)
解説クラスCopyClear(16)
2025年1月20初講(初稿)
この講義は解説『解説クラスCopyClear(15)』
の続きです!
(4-14-38)関数「int MagnifyImage(TypeArray* ps,TypeArray* pd,double zh,double zv,int dataSize,int sw){・・・}」の説明
/************************************************************************/
/***** 正規に見える関数群 *****/
/************************************************************************/
int CopyClear:: MagnifyImage( // 画像の拡大・縮小
TypeArray* ps, // S配列
TypeArray* pd, // D配列
double zh, // 水平拡大率
double zv, // 垂直拡大率
int dataSize, // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
int izh; // 水平拡大率:整数値
int izv; // 垂直拡大率:整数値
if( sw ){ // 補間する場合は
return( MagnifyZoomInterpolate( // 左記で補間付きの
ps, pd, zh, zv, 0.0, 0.0, dataSize ) ); // 拡大・縮小処理
} //
if( zh >= 1.0 && zv >= 1.0 ){ // 拡大時で
izh = (int)zh; // 整数の拡大率を
izv = (int)zv; // 求め
if( (double)izh == zh && (double)izv == zv ){ // 整数倍で拡大の場合
return( MagnifyZoomInt( ps, pd, izh, izv, // 左記で拡大
dataSize ) ); //
} //
} // 実数値での指定では
return( MagnifyZoom( ps, pd, zh, zv, dataSize ) ); // 左記で拡大・縮小処理
}
☆備考☆この関数はファイル「CopyClear.cpp」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
★備考★「C言語のコード部、関数本体の前のコメントに
【正規に見える関数群】」と有るのは、アルゴリズム解説で
説明する様にサブルーチン関数「MagnifyZoomInterpolate」
「MagnifyZoomint 」・「MagnifyZoom」と複数の良く似て細かく違う関数を大本の「正規」名称≪MagnifyImage≫の
名前でマトメタからです!
(A)関数「MagnifyImage()」の【関数名】説明
「Magnify」は、英単語「magnify」で拡大するとの意味です!
「Image」は、勿論、画像で、ココでは、拡大の一部としてと意味も拡大して「画像の拡大/縮小」を行う関数です!
(B)関数「int MagnifyImage()」の【返値】説明
基本的に内部で使用するサブルーチン関数の辺値をこの関数
の辺値とします!
(C)関数「MagnifyImage()」の【仮引数】説明
int CopyClear:: MagnifyImage( // 画像の拡大・縮小
TypeArray* ps, // S配列
TypeArray* pd, // D配列
double zh, // 水平拡大率
double zv, // 垂直拡大率
int dataSize, // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
「TypeArray* ps,」は、S(元)画像情報
「TypeArray* pd,」は、D(結果)画像情報
「double zh,」は、水平方向(X座標方向)の拡大率です!
「double zv,」は、垂直方向(Y座標方向)の拡大率です!
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
「int sw=FALSE);」は、画素間の補完を行うか否かです!
省略時は補完で無く高速化処理です
(D)関数「MagnifyImage()」の【アルゴリズム】説明
){
int izh; // 水平拡大率:整数値
int izv; // 垂直拡大率:整数値
if( sw ){ // 補間する場合は
return( MagnifyZoomInterpolate( // 左記で補間付きの
ps, pd, zh, zv, 0.0, 0.0, dataSize ) ); // 拡大・縮小処理
} //
if( zh >= 1.0 && zv >= 1.0 ){ // 拡大時で
izh = (int)zh; // 整数の拡大率を
izv = (int)zv; // 求め
if( (double)izh == zh && (double)izv == zv ){ // 整数倍で拡大の場合
return( MagnifyZoomInt( ps, pd, izh, izv, // 左記で拡大
dataSize ) ); //
} //
} // 実数値での指定では
return( MagnifyZoom( ps, pd, zh, zv, dataSize ) ); // 左記で拡大・縮小処理
}
(D-1)ローカル変数
){
int izh; // 水平拡大率:整数値
int izv; // 垂直拡大率:整数値
「int izh;」は、水平方向の拡大率の整数化値
「int izv;」は、垂直方向の拡大率の整数化値
(D-2)アルゴリズムコード
if( sw ){ // 補間する場合は
return( MagnifyZoomInterpolate( // 左記で補間付きの
ps, pd, zh, zv, 0.0, 0.0, dataSize ) ); // 拡大・縮小処理
} //
if( zh >= 1.0 && zv >= 1.0 ){ // 拡大時で
izh = (int)zh; // 整数の拡大率を
izv = (int)zv; // 求め
if( (double)izh == zh && (double)izv == zv ){ // 整数倍で拡大の場合
return( MagnifyZoomInt( ps, pd, izh, izv, // 左記で拡大
dataSize ) ); //
} //
} // 実数値での指定では
return( MagnifyZoom( ps, pd, zh, zv, dataSize ) ); // 左記で拡大・縮小処理
}
「if(sw){return(MagnifyZoomInterpolate(
ps,pd,zh,zv,0.0,0.0,dataSize));}」は、条件「sw」が真
なら「return(MagnifyZoomInterpolate(
ps,pd,zh,zv,0.0,0.0,dataSize));}」とサブルーチン
関数「MagnifyZoomInterpolate()」で処理し、この関数の
辺値を返し関数終了!
条件「zh>=1.0&&zv>=1.0」と水平・垂直方向の拡大率が、
両方とも1.0以上≪詰り、拡大する場合≫、一旦、
「izh=(int )zh;izv=(int )zv;」と整数化拡大率をセットし
条件「if((double)izh==zh&&(double)izv==zv)」と整数化
した値と拡大率が同じ≪詰り、整数倍拡大する場合≫なら
「return(MagnifyZoomInt(ps,pd,izh,izv,dataSize
));」とサブルーチン関数「MagnifyZoomInt()」で処理し、
この関数の辺値を返し関数終了!
これ等の条件の外ならば、
「return(MagnifyZoom(ps,pd,zh,zv,dataSize));」で
サブルーチン関数「MagnifyZoom()」で処理し、この関数の
辺値を返し関数終了!
(E)関数「MagnifyImage()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
(4-14-39)関数「int MoveImage(TypeArray* ps,TypeArray* pd,double x,double y,int dataSize,int sw){・・・}」の説明
/************************************************************************/
/***** 図形の平行移動:実行部:配列版 *****/
/************************************************************************/
int CopyClear::MoveImage(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double x, // X座標
double y, // Y座標
int dataSize, // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
TypeArray S; // S画像情報
TypeArray S1; // S画像情報
TypeArray D; // D画像情報
TypeArray D1; // D画像情報
int iX; // X座標整数
int iY; // Y座標整数
double offsetX; // 微少X座標offset(0.0~1.0)
double offsetY; // 微少Y座標offset(0.0~1.0)
int st1; // ステータス情報
int st2; // ステータス情報
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( sw ){ // 補間がある場合
iX = (int)x; // X座標を整数部と
offsetX = x - (double)iX; // 微少部に分離
if( offsetX < 0.0 ){ // 負なら
offsetX += 1.0; // 左記のように
iX -= 1; // 補正
} //
iY = (int)y; // Y座標を整数部と
offsetY = y - (double)iY; // 微少部に分離
if( offsetY < 0.0 ){ // 負なら
offsetY += 1.0; // 左記のように
iY -= 1; // 補正
} //
}else{ // 補間がない場合
iX = (int)x; // X座標を整数部と
offsetX = 0.0; // 微少部に分離
iY = (int)y; // Y座標を整数部と
offsetY = 0.0; // 微少部に分離
} //
if( dataSize >= 2 ){ // 画素サイズ2以上なら
iX *= dataSize; // 論理座標を物理座標に変換
} //
if( iX >= 0 ){ // Xが正の場合
st1 = S.subsetAdjust( ps, 0, 0, ps->h, ps->v ); // Sは元のまま
st2 = D.subsetAdjust( pd, iX, 0, pd->h - iX, pd->v ); // DをX座標ずらし
}else{ // Xが負の場合
st1 = S.subsetAdjust( ps, -iX, 0, ps->h + iX, ps->v ); // SをX座標ずらし
st2 = D.subsetAdjust( pd, 0, 0, pd->h, pd->v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( iY >= 0 ){ // Yが正の場合
st1 = S1.subsetAdjust( &S, 0, 0, S.h, S.v ); // Sは元のまま
st2 = D1.subsetAdjust( &D, 0, iY, D.h, D.v - iY ); // DをY座標ずらし
}else{ // Yが負の場合
st1 = S1.subsetAdjust( &S, 0, -iY, S.h, S.v + iY ); // SをY座標ずらし
st2 = D1.subsetAdjust( &D, 0, 0, D.h, D.v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( !sw || offsetX == 0.0 && offsetY == 0.0 ){ // 整数分移動する場合
return( Copy( &S1, &D1 ) ); // 左記で画像コピー
}else{ // 実数で移動する場合
if( ps->w == 1 ){ // 1Byte画素単位なら
return( MoveImageByte( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 2 ){ // 2Byte画素単位なら
return( MoveImageShort( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 4 ){ // 4Byte画素単位なら
return( MoveImageLong( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 101 ){ // 単精度画素単位なら
return( MoveImageFloat( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else{ // 上記以外なら
return( STI_ARY_5 ); // 不正を返す
} //
} //
}
☆備考☆この関数はファイル「CopyClear350.cpp」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
(A)関数「MoveImage()」の【関数名】説明
「Move」は、英単語「Move」でカタカナ語でムーブ、ココ
では、画像の位置の幾何的移動を行う処理です!
(B)関数「int MoveImage()」の【返値】説明
この関数内で明示的に検査しているのは、内部で使用する
部分画像生成が可能か否かで部分画像生成が出来なかった
時にソノ失敗時エラーコードを関数の辺値とし返し、
関数終了します!そしてサブルーチン関数で移動処理時に
発生したエラーコードを関数の値として返し関数終了!
(C)関数「MoveImage()」の【仮引数】説明
int CopyClear::MoveImage(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
double x, // X座標
double y, // Y座標
int dataSize, // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
「TypeArray* ps,」は、S(元)画像情報
「TypeArray* pd,」は、D(結果)画像情報
「double x,」は、移動先のX座標
「double y,」は、移動先のY座標
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
「int sw=FALSE);」は、画素間の補完を行うか否かです!
省略時は補完で無く高速化処理です
(D)関数「MoveImage()」の【アルゴリズム】説明
){
TypeArray S; // S画像情報
TypeArray S1; // S画像情報
TypeArray D; // D画像情報
TypeArray D1; // D画像情報
int iX; // X座標整数
int iY; // Y座標整数
double offsetX; // 微少X座標offset(0.0~1.0)
double offsetY; // 微少Y座標offset(0.0~1.0)
int st1; // ステータス情報
int st2; // ステータス情報
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( sw ){ // 補間がある場合
iX = (int)x; // X座標を整数部と
offsetX = x - (double)iX; // 微少部に分離
if( offsetX < 0.0 ){ // 負なら
offsetX += 1.0; // 左記のように
iX -= 1; // 補正
} //
iY = (int)y; // Y座標を整数部と
offsetY = y - (double)iY; // 微少部に分離
if( offsetY < 0.0 ){ // 負なら
offsetY += 1.0; // 左記のように
iY -= 1; // 補正
} //
}else{ // 補間がない場合
iX = (int)x; // X座標を整数部と
offsetX = 0.0; // 微少部に分離
iY = (int)y; // Y座標を整数部と
offsetY = 0.0; // 微少部に分離
} //
if( dataSize >= 2 ){ // 画素サイズ2以上なら
iX *= dataSize; // 論理座標を物理座標に変換
} //
if( iX >= 0 ){ // Xが正の場合
st1 = S.subsetAdjust( ps, 0, 0, ps->h, ps->v ); // Sは元のまま
st2 = D.subsetAdjust( pd, iX, 0, pd->h - iX, pd->v ); // DをX座標ずらし
}else{ // Xが負の場合
st1 = S.subsetAdjust( ps, -iX, 0, ps->h + iX, ps->v ); // SをX座標ずらし
st2 = D.subsetAdjust( pd, 0, 0, pd->h, pd->v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( iY >= 0 ){ // Yが正の場合
st1 = S1.subsetAdjust( &S, 0, 0, S.h, S.v ); // Sは元のまま
st2 = D1.subsetAdjust( &D, 0, iY, D.h, D.v - iY ); // DをY座標ずらし
}else{ // Yが負の場合
st1 = S1.subsetAdjust( &S, 0, -iY, S.h, S.v + iY ); // SをY座標ずらし
st2 = D1.subsetAdjust( &D, 0, 0, D.h, D.v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( !sw || offsetX == 0.0 && offsetY == 0.0 ){ // 整数分移動する場合
return( Copy( &S1, &D1 ) ); // 左記で画像コピー
}else{ // 実数で移動する場合
if( ps->w == 1 ){ // 1Byte画素単位なら
return( MoveImageByte( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 2 ){ // 2Byte画素単位なら
return( MoveImageShort( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 4 ){ // 4Byte画素単位なら
return( MoveImageLong( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 101 ){ // 単精度画素単位なら
return( MoveImageFloat( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else{ // 上記以外なら
return( STI_ARY_5 ); // 不正を返す
} //
} //
}
(D-1)ローカル変数
){
TypeArray S; // S画像情報
TypeArray S1; // S画像情報
TypeArray D; // D画像情報
TypeArray D1; // D画像情報
int iX; // X座標整数
int iY; // Y座標整数
double offsetX; // 微少X座標offset(0.0~1.0)
double offsetY; // 微少Y座標offset(0.0~1.0)
int st1; // ステータス情報
int st2; // ステータス情報
「TypeArrayS;」は、S(元)画像の部分画像:X座標変位
「TypeArrayS1;」は、S(元)画像の部分画像:Y座標変位
「TypeArrayD;」は、D(結果)画像の部分画像:X座標変位
「TypeArrayD1;」は、D(結果)画像の部分画像:Y座標変位、
「int iX;」は、整数化したX座標変位
「int iY;」は、整数化したY座標変位
「double offsetX;」は、X座標変位の小数点以下部分
「double offsetY;」は、Y座標変位の小数点以下部分
「int st1;」は、ステータス(エラー)情報
「int st2;」は、ステータス(エラー)情報
(D-2)アルゴリズムコード
if( dataSize <= 0 ){ // 画素サイズ不正なら
return( STI_FLG ); // 不正を返す
} //
if( sw ){ // 補間がある場合
iX = (int)x; // X座標を整数部と
offsetX = x - (double)iX; // 微少部に分離
if( offsetX < 0.0 ){ // 負なら
offsetX += 1.0; // 左記のように
iX -= 1; // 補正
} //
iY = (int)y; // Y座標を整数部と
offsetY = y - (double)iY; // 微少部に分離
if( offsetY < 0.0 ){ // 負なら
offsetY += 1.0; // 左記のように
iY -= 1; // 補正
} //
}else{ // 補間がない場合
iX = (int)x; // X座標を整数部と
offsetX = 0.0; // 微少部に分離
iY = (int)y; // Y座標を整数部と
offsetY = 0.0; // 微少部に分離
} //
if( dataSize >= 2 ){ // 画素サイズ2以上なら
iX *= dataSize; // 論理座標を物理座標に変換
} //
if( iX >= 0 ){ // Xが正の場合
st1 = S.subsetAdjust( ps, 0, 0, ps->h, ps->v ); // Sは元のまま
st2 = D.subsetAdjust( pd, iX, 0, pd->h - iX, pd->v ); // DをX座標ずらし
}else{ // Xが負の場合
st1 = S.subsetAdjust( ps, -iX, 0, ps->h + iX, ps->v ); // SをX座標ずらし
st2 = D.subsetAdjust( pd, 0, 0, pd->h, pd->v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( iY >= 0 ){ // Yが正の場合
st1 = S1.subsetAdjust( &S, 0, 0, S.h, S.v ); // Sは元のまま
st2 = D1.subsetAdjust( &D, 0, iY, D.h, D.v - iY ); // DをY座標ずらし
}else{ // Yが負の場合
st1 = S1.subsetAdjust( &S, 0, -iY, S.h, S.v + iY ); // SをY座標ずらし
st2 = D1.subsetAdjust( &D, 0, 0, D.h, D.v ); // Dは元のまま
} //
if( st1 != END_STI ){ // 不正があれば
return( st1 ); // ステータスを返す
} //
if( st2 != END_STI ){ // 不正があれば
return( st2 ); // ステータスを返す
} //
if( !sw || offsetX == 0.0 && offsetY == 0.0 ){ // 整数分移動する場合
return( Copy( &S1, &D1 ) ); // 左記で画像コピー
}else{ // 実数で移動する場合
if( ps->w == 1 ){ // 1Byte画素単位なら
return( MoveImageByte( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 2 ){ // 2Byte画素単位なら
return( MoveImageShort( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 4 ){ // 4Byte画素単位なら
return( MoveImageLong( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else if( ps->w == 101 ){ // 単精度画素単位なら
return( MoveImageFloat( // 左記で平行移動
&S1, &D1, offsetX, offsetY, dataSize ) ); // (補間付き)
}else{ // 上記以外なら
return( STI_ARY_5 ); // 不正を返す
} //
} //
}
「if(dataSize<=0){return(STI_FLG);}」は、画素単位が、
0以下をエラーとし「STI_FLG」を返し関数終了!
「if(sw){・・成立中身・・}else{・・不成立中身・・}」
は、成立条件「sw」詰り、補完する場合は、
成立中身「iX=(int )x;offsetX=x-(double)iX;
if(offsetX<0.0){offsetX+=1.0;iX-=1;}
iY=(int )y;offsetY=y-(double)iY;
if(offsetY<0.0){offsetY+=1.0;iY-=1;}」と
「iX=(int )x;offsetX=x-(double)iX;」で変数「ix」に
X座標の整数値部をセットし変数「offsetX」に小数点
以下の部分をセットします!そして
「if(offsetX<0.0){offsetX+=1.0;iX-=1;}」でX座標の
小数点以下部分が負の値なら、「offsetX+=1.0;iX-=1;」
と整数値部・小数点以下部分を正の数に成る様に補正!
「iY=(int )y;offsetY=y-(double)iY;」で変数「iy」に
Y座標の整数値部をセットし変数「offsetY」に小数点
以下の部分をセットします!そして
「if(offsetY<0.0){offsetY+=1.0;iY-=1;}」でY座標の
小数点以下部分が負の値なら、「offsetY+=1.0;iY-=1;」
と整数値部・小数点以下部分を正の数に成る様に補正!
不成立中身「iX=(int )x;offsetX=0.0;
iY=(int )y;offsetY=0.0;」は、勿論、座標補正しないので
「iX=(int )x;offsetX=0.0;」と整数部分は型変換だけ行い
小数点以下部分が0.0にセットがX座標方向でY座標方向
も「iY=(int )y;offsetY=0.0;」整数部分は型変換だけ行い
小数点以下部分が0.0にセット!
「if(dataSize>=2){iX*=dataSize;}」は、
条件「dataSize>=2」、詰り2画素単位以上なら
「iX*=dataSize;」でX座標方向の整数化部分を画素単位に
補正!
「if(iX>=0){・・成立中身・・}else{・・成立中身・・}」
は、条件「iX>=0」とX座標方向整数部が0以上で成立中身
「st1=S.subsetAdjust(ps,0,0,ps->h,ps->v);
st2=D.subsetAdjust(pd,iX,0,pd->h-iX,pd->v);」で
「S.subsetAdjust()」と「TypeArray」クラスのメンバー
関数「subsetAdjust()」で部分画像をローカル画像情報
「S」にセットし、
メンバー関数実行ステータス情報を変数「st1」
にセットします、
同じ様に部分画像をローカル画像情報「D」にセットし、
メンバー関数実行ステータス情報を変数「st2」にセット
します!★備考★【主にC言語だけに馴染んで来た
受講生の皆様へ、このC++言語から使える様に成ったクラ
スのメンバー関数を使用する方法をこのライブラリは多用し
ていますので慣れて下さい★注意★この様にクラスに限定し
た使用方法はオブジェクト指向の考えとして不用意に他で使
え無い事でソースコードの安全性を高める手法と理解して下
さい】
不成立中身「st1=S.subsetAdjust(
ps,-iX,0,ps->h+iX,ps->v);st2=D.subsetAdjust(
pd,0,0,pd->h,pd->v);」は、整数部が負数に成ったら、座標
始点を始終を逆にして部分画像を取得している事は字面から
理解して頂けると思いますが?!理解して頂いていますね!
「if(st1!=END_STI){return(st1);}」は、ステータス情報
「st1」にエラーが有れば、このコードの値を関数の値とし
返し関数終了!
「if(st2!=END_STI){return(st2);}」は、ステータス情報
「st1」にエラーが有れば、このコードの値を関数の値とし
返し関数終了!★注意★ここまででX座標方向の部分画像
を作成した事を理解して下さい!
「if(iY>=0){・・・・if(st2!=END_STI){return(st2);}」
は、今度は、Y座標方向の部分画像を作成した事を理解して
頂けますね!
「if(!sw||offsetX==0.0&&offsetY==0.0){・・成立中身・・
}else{・・不成立中身・・}」は、条件「
!sw||offsetX==0.0&&offsetY==0.0」、詰り、補正無し及び
XY座標の小数点以下移動部分が無い場合と例外条件と考え
て頂ければ良いかなで「return(Copy(&S1,&D1));」と
サブルーチン関数「Copy(&S1,&D1)」で処理し、その辺値を
関数の辺値として関数終了!★備考★幾何移動で画素単位の
場合は、画像処理の基本中の基本的なコピー関数で十分と言
う事です!そして「}else{・・不成立中身・・}」と細かい
小数点以下の移動も扱う処理では、
「if(ps->w==1){return(MoveImageBYTE (&S1,&D1,offsetX,
offsetY,dataSize));」と条件「ps->w==1」画素単位が、
1バイトの時、「return(MoveImageBYTE (&S1,&D1,
offsetX,offsetY,dataSize));」とサブルーチン関数「
MoveImageBYTE ()」で処理し、その辺値を関数の辺値として
関数終了!
「}else if(ps->w==2){return(MoveImageShort(&S1,&D1,
offsetX,offsetY,dataSize));」と条件「ps->w==2」画素
単位が2バイトの時、「return(MoveImageShort(
&S1,&D1,offsetX,offsetY,dataSize));」とサブルーチン
関数「MoveImageShort()」で処理し、その辺値を関数の
辺値として関数終了!
「}else if(ps->w==4){return(MoveImageLong(&S1,&D1,
offsetX,offsetY,dataSize));」と条件「ps->w==4」画素
単位が4バイトの時、「return(MoveImageLong(
&S1,&D1,offsetX,offsetY,dataSize));」とサブルーチン
関数「MoveImageLong()」で処理し、その辺値を関数の
辺値として関数終了!そして、「}else{」と全て非成立の
時は、「return(STI_ARY_5);」とエラーコードを辺値とし
関数終了!
(E)関数「MoveImage()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
(4-14-40)関数「int MirrorImage(TypeArray* ps,TypeArray* pd,int k,int dataSize){・・・}」
/************************************************************************/
/***** 配列の鏡像の作成(上下・左右等図形の変換)コマンド:実行部 *****/
/***** MIRROR,s,d,k *****/
/************************************************************************/
int CopyClear::MirrorImage(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
int k, // 1:左右反転
// 2:上下反転
// 3:上下左右反転
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
TypeArray D; // D配列:局所
BYTE *psa; // S配列実Adr
BYTE *pda; // D配列実Adr
int h; // 水平幅
int v; // 垂直幅
int sl; // Sの増加幅
int dl; // Dの増加幅
if( ps == 0 ){ // Sが空なら
return( STI_ARY_0 - 10 ); // 不正を返す
}else if( ps->adr == 0 ){ // Sの実ptrが空なら
return( STI_ARY_1 - 10 ); // 不正を返す
}else if( pd == 0 ){ // Dが空なら
return( STI_ARY_0 - 20 ); // 不正を返す
}else if( pd->adr == 0 ){ // Dの実ptrが空なら
return( STI_ARY_1 - 20 ); // 不正を返す
}else if( ps->w != pd->w || ps->w < 0 // Bits幅が異なるか
|| ps->w == 3 || ps->w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 - 20 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
psa = (BYTE*)ps->adr; // S実Adr取出し
pda = (BYTE*)pd->adr; // D実Adr取出し
h = (ps->h < pd->h) ? ps->h : pd->h; // 水平幅を算出
v = (ps->v < pd->v) ? ps->v : pd->v; // 垂直幅を算出
sl = ps->inc; // Sの増加幅Set
dl = pd->inc; // Dの増加幅Set
if( h % dataSize != 0 ){ // 水平幅が中途なら
h = ( h / dataSize ) * dataSize; // 左記で補正する
} //
if( ps->w == 1 ){ // 1バイト版なら
mirrorByte( psa, pda, h, v, sl, dl, k, // 左記で実行
dataSize ); //
}else if( ps->w == 2 ){ // 2バイト版なら
mirrorShort( (short *)psa, (short *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
}else if( ps->w == 4 ){ // 4バイト版なら
mirrorLong( (long *)psa, (long *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
} //
return( END_STI ); // 正常終了
}
☆備考☆この関数はファイル「CopyClear310」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
★注意★この関数には、同名で仮引数が異なるオーバーロー
ド(多重定義)関数が存在します!
(A)関数「MirrorImage()」の【関数名】
「Mirror」は、英単語「Mirror」で鏡・鏡像、ココでは、
画像の左右を始め上下・上下左右の幾何的鏡像処理です!
(B)関数「int MirrorImage()」の【返値】
この関数内で明示的に検査しているのは、S(元)画像情報
とD(結果)画像情報が正常な画像か両方とも同じ画素単位
か処理可能なサイズか否かを判定し対象外ならばエラーコー
ドに画像エラーコードの意味を返し関数の辺値とし関数終了
及び、鏡像の種類選択肢が規定外(1から3以外)ならば、
エラーコード「STI_FLG」を返し関数の辺値とし関数終了!
(C)関数「MirrorImage()」の【仮引数】
int CopyClear::MirrorImage(
TypeArray *ps, // S配列
TypeArray *pd, // D配列
int k, // 1:左右反転
// 2:上下反転
// 3:上下左右反転
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
「TypeArray* ps,」は、S(元)画像情報
「TypeArray* pd,」は、D(結果)画像情報
「int k,」は、鏡像種類≪1:左右、2:上下、
3:上下左右≫
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
(D)関数「MirrorImage()」の【アルゴリズム】
){
TypeArray D; // D配列:局所
BYTE *psa; // S配列実Adr
BYTE *pda; // D配列実Adr
int h; // 水平幅
int v; // 垂直幅
int sl; // Sの増加幅
int dl; // Dの増加幅
if( ps == 0 ){ // Sが空なら
return( STI_ARY_0 - 10 ); // 不正を返す
}else if( ps->adr == 0 ){ // Sの実ptrが空なら
return( STI_ARY_1 - 10 ); // 不正を返す
}else if( pd == 0 ){ // Dが空なら
return( STI_ARY_0 - 20 ); // 不正を返す
}else if( pd->adr == 0 ){ // Dの実ptrが空なら
return( STI_ARY_1 - 20 ); // 不正を返す
}else if( ps->w != pd->w || ps->w < 0 // Bits幅が異なるか
|| ps->w == 3 || ps->w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 - 20 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
psa = (BYTE*)ps->adr; // S実Adr取出し
pda = (BYTE*)pd->adr; // D実Adr取出し
h = (ps->h < pd->h) ? ps->h : pd->h; // 水平幅を算出
v = (ps->v < pd->v) ? ps->v : pd->v; // 垂直幅を算出
sl = ps->inc; // Sの増加幅Set
dl = pd->inc; // Dの増加幅Set
if( h % dataSize != 0 ){ // 水平幅が中途なら
h = ( h / dataSize ) * dataSize; // 左記で補正する
} //
if( ps->w == 1 ){ // 1バイト版なら
mirrorByte( psa, pda, h, v, sl, dl, k, // 左記で実行
dataSize ); //
}else if( ps->w == 2 ){ // 2バイト版なら
mirrorShort( (short *)psa, (short *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
}else if( ps->w == 4 ){ // 4バイト版なら
mirrorLong( (long *)psa, (long *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
} //
return( END_STI ); // 正常終了
}
(D-1)ローカル変数
){
TypeArray D; // D配列:局所
BYTE *psa; // S配列実Adr
BYTE *pda; // D配列実Adr
int h; // 水平幅
int v; // 垂直幅
int sl; // Sの増加幅
int dl; // Dの増加幅
「TypeArrayD;」は、不使用★注意★削除し忘れ
「BYTE *psa;」は、S画像実処理ポインタ
「BYTE *pda;」は、D画像実処理ポインタ
「int h;」は、水平幅
「int v;」は、垂直幅
「int sl;」は、S画像増加幅
「int dl;」は、D画像増加幅
(D-2)アルゴリズムコード
if( ps == 0 ){ // Sが空なら
return( STI_ARY_0 - 10 ); // 不正を返す
}else if( ps->adr == 0 ){ // Sの実ptrが空なら
return( STI_ARY_1 - 10 ); // 不正を返す
}else if( pd == 0 ){ // Dが空なら
return( STI_ARY_0 - 20 ); // 不正を返す
}else if( pd->adr == 0 ){ // Dの実ptrが空なら
return( STI_ARY_1 - 20 ); // 不正を返す
}else if( ps->w != pd->w || ps->w < 0 // Bits幅が異なるか
|| ps->w == 3 || ps->w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 - 20 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
psa = (BYTE*)ps->adr; // S実Adr取出し
pda = (BYTE*)pd->adr; // D実Adr取出し
h = (ps->h < pd->h) ? ps->h : pd->h; // 水平幅を算出
v = (ps->v < pd->v) ? ps->v : pd->v; // 垂直幅を算出
sl = ps->inc; // Sの増加幅Set
dl = pd->inc; // Dの増加幅Set
if( h % dataSize != 0 ){ // 水平幅が中途なら
h = ( h / dataSize ) * dataSize; // 左記で補正する
} //
if( ps->w == 1 ){ // 1バイト版なら
mirrorByte( psa, pda, h, v, sl, dl, k, // 左記で実行
dataSize ); //
}else if( ps->w == 2 ){ // 2バイト版なら
mirrorShort( (short *)psa, (short *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
}else if( ps->w == 4 ){ // 4バイト版なら
mirrorLong( (long *)psa, (long *)pda, // 左記で実行
h, v, sl, dl, k, dataSize ); //
} //
return( END_STI ); // 正常終了
}
「if(ps==0){return(STI_ARY_0-10);}」は、条件「ps==0」
とS画像情報ポインタ自体が空ならエラーコード「
STI_ARY_0-10」と最初の画像情報にエラーが有る事も
含めたエラーコードを辺値とし返し関数終了!
「else if(ps->adr==0){return(STI_ARY_1-10);}」は、
条件「ps->adr==0」とS画像実処理ポインタが空なら、
エラーコード「STI_ARY_1-10」と最初の画像情報にエラー
が有る事も含めたエラーコードを辺値とし返し関数終了!
「else if(pd==0){return(STI_ARY_0-20);}」は、
条件「pd==0」とD画像情報ポインタ自体が空ならエラー
コード「STI_ARY_0-20」と2番の画像情報にエラーが有る
事も含めたエラーコードを辺値とし返し関数終了!
「else if(pd->adr==0){return(STI_ARY_1-20);}」は、
条件「pd->adr==0」とD画像実処理ポインタが空なら、
エラーコード「STI_ARY_1-20」と2番の画像情報にエラー
が有る事も含めたエラーコードを辺値とし返し関数終了!
「else if(ps->w!=pd->w||ps->w<0||ps->w==3||ps->w>4){
return(STI_ARY_5-20);}」は、条件「ps->w!=pd->w||
ps->w<0||ps->w==3||ps->w>4」と画素単位が異なるか、
ここで処理可能な画素単位で無い場合を判定し、成立時は
「STI_ARY_5-20」で2番の画像情報が「STI_ARY_5」を発生
させたと判定し、エラーコードを辺値とし返し関数終了!
「if(k<=0||k>3||dataSize<=0){return(STI_FLG);}」は、
鏡像の種類が1から3の範囲に入って居るか否かと処理する
画素数が0未満ならエラーコード「STI_FLG」を辺値とし
返し関数終了!
「psa=(BYTE *)ps->adr;pda=(BYTE *)pd->adr;」は、
SD両画像の実処理ポインタを使い易いローカル変数に
セット、
「h=(ps->h<pd->h)?ps->h:pd->h;
v=(ps->v<pd->v)?ps->v:pd->v;」は、水平垂直幅の有効幅
として処理する最小値を算出しローカル変数にセット、
「if(h%dataSize!=0){h=(h/dataSize)*dataSize;}」は、
水平幅が処理する画素数単位の倍数に成って無ければ、
倍数に成る様に一単位少ない幅で補正!
「if(ps->w==1){mirrorBYTE (psa,pda,h,v,sl,dl,k,
dataSize);}」は、条件「ps->w==1」で画素単位が1バイト
単位の場合、サブルーチン関数「mirrorBYTE ()」で処理
★注意★このサブルーチン関数ではエラーは発生しないとし
ステータス情報は取得しません!
「else if(ps->w==2){mirrorShort((short *)psa,
(short *)pda,h,v,sl,dl,k,dataSize);}」は、
条件「ps->w==2」で画素単位が2バイト
単位の場合、サブルーチン関数「mirrorShort()」で処理
★注意★このサブルーチン関数もラーは発生しないとし
ステータス情報は取得しません!
「else if(ps->w==4){mirrorLong((long *)psa,
(long *)pda,h,v,sl,dl,k,dataSize);}」は、
条件「ps->w==4」で画素単位が4バイト
単位の場合、サブルーチン関数「mirrorLong()」で処理
★注意★このサブルーチン関数もラーは発生しないとし
ステータス情報は取得しません!
「return(END_STI);」は、正常終了を返し関数終了!
(E)関数「MirrorImage()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
(4-14-41)関数「int MirrorImage(TypeArray* image,int k,int dataSiz){・・・}」
/************************************************************************/
/***** 配列の鏡像の作成(上下・左右等図形の変換)コマンド:実行部 *****/
/***** ☆自分自身の鏡像作成☆ *****/
/************************************************************************/
int CopyClear::MirrorImage(
TypeArray* image, // 画像
int k, // 1:左右反転
// 2:上下反転
// 3:上下左右反転
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
TypeArray s; // S画像
TypeArray d; // D画像
TypeArray t; // T画像
int w; // 単位
int h; // 水平幅
int v; // 垂直幅
int h2; // 水平幅÷2
int v2; // 垂直幅÷2
int sti; // ステータス情報
if( image == 0 ){ // 画像が空なら
return( STI_ARY_0 ); // 不正を返す
}else if( image->adr == 0 ){ // 画像の実ptrが空なら
return( STI_ARY_1 ); // 不正を返す
}else if( ( h = image->h ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_2 ); // 不正を返す
}else if( ( v = image->v ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_3 ); // 不正を返す
}else if( ( w = image->w ) < 0 || w == 3 || w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
if( k == 2 ){ // 上下反転時は
v2 = v / 2; // 垂直幅÷2算出
s.subset( image, 0, 0, h, v2 ); // 上半分画像作成
d.subset( image, 0, v2, h, v2 ); // 下半分画像作成
sti = t.Malloc( w, h, v2 ); // 左記でメモリ確保
}else{ // 左右反転時は
h2 = h / 2; // 水平幅÷2算出
if( h2 % dataSize != 0 ){ // 水平幅が中途なら
h2 = ( h2 / dataSize ) * dataSize; // 左記で補正する
} //
s.subset( image, 0, 0, h2, v ); // 左半分画像作成
d.subset( image, h2, 0, h2, v ); // 右半分画像作成
sti = t.Malloc( w, h2, v ); // 左記でメモリ確保
} //
if( sti == END_STI ){ // メモリ確保成功時
Copy( &d, &t ); // D→T
MirrorImage( &s, &d, k, dataSize ); // S→D:鏡像処理
MirrorImage( &t, &s, k, dataSize ); // T→S:鏡像処理
t.freeMem(); // T画像メモリ解放
return( END_STI ); // 正常終了
} //
return( sti ); // ステータスを返す
}
☆備考☆この関数はファイル「CopyClear310」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
★注意★この関数には、同名で仮引数が異なるオーバーロー
ド(多重定義)関数が存在します!
(A)関数「MirrorImage()」の【関数名】
「Mirror」は、英単語「Mirror」で鏡・鏡像、ココでは、
画像の左右を始め上下・上下左右の幾何的鏡像処理です!
(B)関数「int MirrorImage()」の【返値】
この関数内で明示的に検査しているのは、画像情報が正常な
画像か処理可能なサイズか否かを判定し対象外ならばエラー
コードに画像エラーコードの意味を返し関数の辺値とし
関数終了、及び、鏡像の種類選択肢が規定外(1から3以外
)ならば、エラーコード「STI_FLG」を返し関数の辺値とし
関数終了!
(C)関数「MirrorImage()」の【仮引数】
int CopyClear::MirrorImage(
TypeArray* image, // 画像
int k, // 1:左右反転
// 2:上下反転
// 3:上下左右反転
int dataSize // 画素サイズ(省略時=1)
// 1:主に濃淡画像
// 3:主にカラー(3原色)画像
){
「TypeArray* image,」は、処理対象の画像★注意★この
関数では、SD両者とも同じ画像です!この関数は、SD
両者を指定する関数に比べて画像と処理の性質から破壊(
内容が書き変わる)されるが、処理速度的に有利に成ります
「int k,」は、鏡像種類≪1:左右、2:上下、
3:上下左右≫
「int dataSize=1,」は、引数省略時は1と1画素単位です
が、3画素をRGBとかのカラー画像に対応出来る様にして
います!
(D)関数「MirrorImage()」の【アルゴリズム】
){
TypeArray s; // S画像
TypeArray d; // D画像
TypeArray t; // T画像
int w; // 単位
int h; // 水平幅
int v; // 垂直幅
int h2; // 水平幅÷2
int v2; // 垂直幅÷2
int sti; // ステータス情報
if( image == 0 ){ // 画像が空なら
return( STI_ARY_0 ); // 不正を返す
}else if( image->adr == 0 ){ // 画像の実ptrが空なら
return( STI_ARY_1 ); // 不正を返す
}else if( ( h = image->h ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_2 ); // 不正を返す
}else if( ( v = image->v ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_3 ); // 不正を返す
}else if( ( w = image->w ) < 0 || w == 3 || w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
if( k == 2 ){ // 上下反転時は
v2 = v / 2; // 垂直幅÷2算出
s.subset( image, 0, 0, h, v2 ); // 上半分画像作成
d.subset( image, 0, v2, h, v2 ); // 下半分画像作成
sti = t.Malloc( w, h, v2 ); // 左記でメモリ確保
}else{ // 左右反転時は
h2 = h / 2; // 水平幅÷2算出
if( h2 % dataSize != 0 ){ // 水平幅が中途なら
h2 = ( h2 / dataSize ) * dataSize; // 左記で補正する
} //
s.subset( image, 0, 0, h2, v ); // 左半分画像作成
d.subset( image, h2, 0, h2, v ); // 右半分画像作成
sti = t.Malloc( w, h2, v ); // 左記でメモリ確保
} //
if( sti == END_STI ){ // メモリ確保成功時
Copy( &d, &t ); // D→T
MirrorImage( &s, &d, k, dataSize ); // S→D:鏡像処理
MirrorImage( &t, &s, k, dataSize ); // T→S:鏡像処理
t.freeMem(); // T画像メモリ解放
return( END_STI ); // 正常終了
} //
return( sti ); // ステータスを返す
}
(D-1)ローカル変数
){
TypeArray s; // S画像
TypeArray d; // D画像
TypeArray t; // T画像
int w; // 単位
int h; // 水平幅
int v; // 垂直幅
int h2; // 水平幅÷2
int v2; // 垂直幅÷2
int sti; // ステータス情報
「TypeArray s;」は、ローカルなS画像情報
「TypeArray d;」は、ローカルなD画像情報
「TypeArray t;」は、ローカルなT(テンポラリ)画像情報
「int w;」は、画素単位
「int h;」は、水平幅
「int v;」は、垂直幅
「int h2;」は、水平幅÷2
「int v2;」は、垂直幅÷2
「int sti;」は、ステータス情報
(D-2)アルゴリズムコード
if( image == 0 ){ // 画像が空なら
return( STI_ARY_0 ); // 不正を返す
}else if( image->adr == 0 ){ // 画像の実ptrが空なら
return( STI_ARY_1 ); // 不正を返す
}else if( ( h = image->h ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_2 ); // 不正を返す
}else if( ( v = image->v ) <= 0 ){ // 画像の水平幅不正時
return( STI_ARY_3 ); // 不正を返す
}else if( ( w = image->w ) < 0 || w == 3 || w > 4 ){ // 可能な幅以外は
return( STI_ARY_5 ); // 不正を返す
} //
if( k <= 0 || k > 3 || dataSize <= 0 ){ // 不正なら
return( STI_FLG ); // 不正を返す
} //
if( k == 2 ){ // 上下反転時は
v2 = v / 2; // 垂直幅÷2算出
s.subset( image, 0, 0, h, v2 ); // 上半分画像作成
d.subset( image, 0, v2, h, v2 ); // 下半分画像作成
sti = t.Malloc( w, h, v2 ); // 左記でメモリ確保
}else{ // 左右反転時は
h2 = h / 2; // 水平幅÷2算出
if( h2 % dataSize != 0 ){ // 水平幅が中途なら
h2 = ( h2 / dataSize ) * dataSize; // 左記で補正する
} //
s.subset( image, 0, 0, h2, v ); // 左半分画像作成
d.subset( image, h2, 0, h2, v ); // 右半分画像作成
sti = t.Malloc( w, h2, v ); // 左記でメモリ確保
} //
if( sti == END_STI ){ // メモリ確保成功時
Copy( &d, &t ); // D→T
MirrorImage( &s, &d, k, dataSize ); // S→D:鏡像処理
MirrorImage( &t, &s, k, dataSize ); // T→S:鏡像処理
t.freeMem(); // T画像メモリ解放
return( END_STI ); // 正常終了
} //
return( sti ); // ステータスを返す
}
「if(image==0){return(STI_ARY_0);}」は、
仮引数「TypeArray* image,」のポインタ自体が空ならば
エラーコード「STI_ARY_0」を辺値とし返し関数終了!
「else if(image->adr==0){return(STI_ARY_1);}」は、
条件「image->adr==0」と実処理ポインタが空ならば
エラーコード「STI_ARY_1」を辺値とし返し関数終了!
「else if((h=image->h)<=0){return(STI_ARY_2);}」は、
条件「h=image->h」と水平幅が0以下ならばエラー
コード「STI_ARY_2」を辺値とし返し関数終了!
「else if((v=image->v)<=0){return(STI_ARY_3);}」は、
条件「v=image->v」と垂直幅が0以下ならばエラー
コード「STI_ARY_3」を辺値とし返し関数終了!
「else if((w=image->w)<0||w==3||w>4){
return(STI_ARY_5);}」は、
条件「(w=image->w)<0||w==3||w>4」と画素単位が、
1、2、4バイト単位以外ならばエラーコード
「STI_ARY_5」を辺値とし返し関数終了!
「if(k<=0||k>3||dataSize<=0){return(STI_FLG);}」は、
条件「k<=0||k>3||dataSize<=0」で鏡像の種類が、
1:左右、2:上下、3:上下左右と正規以外と処理する
画素サイズ「dataSize」が0以下の場合、エラーコード
「STI_FLG」を辺値とし返し関数終了!
「if(k==2){・・成立中身・・}」は、条件「k==2」詰り、
上下逆にする処理を成立中身で
「v2=v/2;s.subset(image,0,0,h,v2);
d.subset(image,0,v2,h,v2);sti=t.Malloc(w,h,v2);」と
「v2=v/2」で垂直幅÷2を「v2」にセットし、
「s.subset(image,0,0,h,v2);」で仮引数「
TypeArray* image,」で示される画像の上半分をローカル
変数「s」にセット、「d.subset(image,0,v2,h,v2);」で
画像の下上半分をローカル変数「d」にセット、更に
「sti=t.Malloc(w,h,v2);」でテンポラリー画像をSD両者
と同じく上下半分のサイズで画像メモリ取得!
「else{・・不成立中身・・}」は、条件「k!=2」詰り、
左右・上下左右逆にする処理で「h2=h/2;
if(h2%dataSize!=0){h2=(h2/dataSize)*dataSize;}
s.subset(image,0,0,h2,v);d.subset(image,h2,0,h2,v);
sti=t.Malloc(w,h2,v);}」と「h2=h/2;」で水平幅÷2を
「h2」にセットし、
「if(h2%dataSize!=0){h2=(h2/dataSize)*dataSize;}」で
ここの条件「h2%dataSize!=0」で処理する画素数単位で
水平幅が割り切れず余りが出る場合、
「h2=(h2/dataSize)dataSize;」水平幅÷2の値を補正、
そして「s.subset(image,0,0,h2,v);
d.subset(image,h2,0,h2,v);sti=t.Malloc(w,h2,v);}」と
仮引数「TypeArray image,」で示される画像の水平幅の
右半分の画像を「s.subset(image,0,0,h2,v);」でS画像
左半分の画像を「d.subset(image,h2,0,h2,v);」でD画像
更に「sti=t.Malloc(w,h,v2);」でテンポラリー画像を
SD両者と同じく上下半分のサイズで画像メモリ取得!
「if(sti==END_STI){・・分岐中身・・}」で
条件「sti==END_STI」と画像メモリ取得に成功した場合、
分岐中身「Copy(&d,&t);MirrorImage(&s,&d,k,dataSize);
MirrorImage(&t,&s,k,dataSize);
t.freeMem();return(END_STI);」で中身の処理ですが、
「Copy(&d,&t)」で一旦、テンポラリー画像へのコピー、
「MirrorImage(&s,&d,k,dataSize);」で二項演算のサブ
ルーチン関数「MirrorImage()」で「S⇒D方向」鏡像
処理し、「MirrorImage(&t,&s,k,dataSize);」で
「テンポラリー画像⇒S方向」鏡像処理する事で画像1枚
鏡像処理を行います!そして「t.freeMem();」でテンポラ
リー画像をメモリ解放し、「return(END_STI);」と
正常終了を辺値とし返し、関数終了!
最後に「return(sti);」でメモリ取得失敗時のエラー
コードを辺値とし返し、関数終了!
(E)関数「MirrorImage()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
(F)関数「MirrorImage()」の【注意】
仮引数「int k,」鏡像種類で「k=3」の時、上下左右鏡像
処理が、ソースコード解説で久し振りに読んで見て違和感を
感じてシマッタ!サブルーチン関数の中身を確認する必要が
有るが、取り敢えず、「k=1」左右鏡像・「k=2」上下
鏡像のみ使用して下さい!作成時は、動作確認している筈だ
が、何かオカシイ?!
(4-14-42)関数「int RotateImage(TypeArray* ps,TypeArray* pd,double a,double x1,double y1,double x2,double y2,int dataSize,int sw){・・・}」
/************************************************************************/
/***** 図形の回転を行うコマンド:実行部:配列版 *****/
/***** 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::RotateImage(
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原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
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, sw ) ); //
} //
if( sw ){ // 補間する場合は
return( RotateImageInterpolate( // 左記で補間付きの
ps, pd, a, x1, y1, x2, y2, dataSize ) ); // 回転
} //
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ビット版なら
rotateByte( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShort( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 || ps->w == 101 ){ // 32ビット版なら
rotateLong( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)adrD, hD, vD, incS, incD, //
dataSize ); //
} //
free( base ); // メモリ解放:BaseTable
free( offset ); // メモリ解放:OffsetTable
return( END_STI ); // 正常終了
}
☆備考☆この関数はファイル「CopyClear320」に存在!
★注意★この関数は「public:」属性ですのでライブラリの
外から使用可能です!
(A)関数「RotateImage()」の【関数名】
「Rotate」は、英単語「Rotate」で回転、ココでは、
画像の二次元表面的な幾何的回転処理です!
(B)関数「int RotateImage()」の【返値】
この関数内で明示的に検査しているのは、画像情報が、
SD両者画素単位が同じか否かで否かを判定し対象外ならば
エラーコードに画像エラーコードの意味を返し関数の辺値と
し関数終了、角度指定が「0.0」の場合は、サブルーチン
関数「MoveImage()」の辺値を関数の辺値とし返し関数終了
そして仮引数「int sw」が真(詰り補完処理を行う)場合は
サブルーチン関数「RotateImageInterpolate()」の辺値を
関数の辺値とし返し関数終了!
そして、内部でメモリ取得して居るので取得に失敗時、
エラーコード「STI_MEM」を返し終了!
それ以外は、「return(END_STI);」と正常終了を返しま
す★注意★何故、細かい引数チェックを行わないかは、
処理不能なパラメータの時は、単にサブルーチン関数で処理
シナイだけで終了するからです!
(C)関数「RotateImage()」の【仮引数】
int CopyClear::RotateImage(
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原色)画像
int sw // 補間SW(真:補間、省略時=偽)
){
「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とかのカラー画像に対応出来る様にして
います!
「int sw=FALSE);」は、画素間の補完を行うか否かです!
省略時は補完で無く高速化処理です
(D)関数「RotateImage()」の【アルゴリズム】
){
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, sw ) ); //
} //
if( sw ){ // 補間する場合は
return( RotateImageInterpolate( // 左記で補間付きの
ps, pd, a, x1, y1, x2, y2, dataSize ) ); // 回転
} //
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ビット版なら
rotateByte( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShort( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 || ps->w == 101 ){ // 32ビット版なら
rotateLong( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)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
「TypeXYI* base;」は、S画像基底XY座標テーブル
「TypeXYI* offset;」は、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, sw ) ); //
} //
if( sw ){ // 補間する場合は
return( RotateImageInterpolate( // 左記で補間付きの
ps, pd, a, x1, y1, x2, y2, dataSize ) ); // 回転
} //
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ビット版なら
rotateByte( base, offset, // 左記で回転実行
(BYTE*)adrS, hS, vS, //
(BYTE*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 2 ){ // 16ビット版なら
rotateShort( base, offset, // 左記で回転実行
(short*)adrS, hS, vS, //
(short*)adrD, hD, vD, incS, incD, //
dataSize ); //
}else if( ps->w == 4 || ps->w == 101 ){ // 32ビット版なら
rotateLong( base, offset, // 左記で回転実行
(long*)adrS, hS, vS, //
(long*)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){rotateBYTE (base,offset,
(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,incS,incD,
dataSize);}」は、選択条件「ps->w==1」で1バイト画素
画像ならば、サブルーチン関数「rotateBYTE (base,offset,(BYTE *)adrS,hS,vS,(BYTE *)adrD,hD,vD,incS,incD,dataSize);」とサブルーチン関数「rotateBYTE ()」で処理します!
「else if(ps->w==2){rotateShort(base,offset,
(short *)adrS,hS,vS,(short *)adrD,hD,vD,incS,incD,dataSize);}」は、選択条件「ps->w==2」で2バイト画素画像ならば、
サブルーチン関数「rotateShort(base,offset,(short*)adrS,
hS,vS,(short *)adrD,hD,vD,incS,incD,dataSize);」と
サブルーチン関数「rotateShort()」で処理します!
「else if(ps->w==4||ps->w==101){rotateLong(base,offset,(long *)adrS,hS,vS,(long *)adrD,hD,vD,incS,incD,dataSize);}」は、選択条件「ps->w==4」で4バイト画素画像ならば、
サブルーチン関数「rotateLong(base,offset,(long *)adrS,hS,
vS,(long *)adrD,hD,vD,incS,incD,dataSize);」と
サブルーチン関数「rotateLong()」で処理します!
★備考★画素単位の選択肢「ps->w==102」と8バイト
倍精度浮動小数点型は用意しませんでした!ライブラリ作成
当時、需要が無いと判断したのですが!ソースコードで公開
していますので必要な方は、このソースコードを参考にして
追加して下さい!私(作者)は、新規に作成したコード動作
保証はできませんので悪しからず!
「free(base);free(offset);」は、メモリ取得した後始末!
「return(END_STI);」は、正常終了を返し関数終了!
(E)関数「RotateImage()」の【使用例】
★注意★
使用例は、別の解説エッセイ『画像幾何変換使用例』で
別途説明する事に方針変換しました!
使用例発表まで乞うご期待と記載して置きます!
本日(1月20)の講義はココまでとします!
流石に新しくと言うか「画像幾何変換」の話に遷ったの
で受講者の皆様が消化出来る為にココまでとします!
次から幾何的回転処理詳細を扱いますので別の解説
解説『解説クラスCopyClear(17)』に続きます