魚眼レンズ風
まさか自分でもできるとは思わなかった魚眼レンズちっくに画像を加工。
private Bitmap effectFisheye( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixelsSrc = new int[( width * height )]; int[] pixelsDest = new int[( width * height )]; bitmap.getPixels( pixelsSrc, 0, width, 0, 0, width, height ); int indexMax = ( width * ( height -1 ) + ( width - 1 ) ); int weight = 40; double radius; if( height < width ){ radius = width / 2; } else { radius = height / 2; } for( int YY = 0; YY < height; ++YY ){ for( int XX = 0; XX < width; ++XX ){ double rp = Math.sqrt( (double)( Math.pow( (double)( weight ), 2 ) + Math.pow( (double)( XX - width / 2 ), 2 ) + Math.pow( (double)( YY - height / 2 ), 2 ) ) ); int XXX = (int)( ( rp * ( XX - width / 2 ) ) / radius + width / 2 ); int YYY = (int)( ( rp * ( YY - height / 2 ) ) / radius + height / 2 ); int srcIndex1 = ( width * YYY + XXX ); int srcIndex2 = srcIndex1 + 1; int srcIndex3 = srcIndex1 + 2; int destIndex1 = ( width * YY + XX ); int destIndex2 = destIndex1 + 1; int destIndex3 = destIndex1 + 2; if( 0 <= XXX && XXX < width && 0 <= YYY && YYY < height ){ if( srcIndex1 <= indexMax && destIndex1 <= indexMax ){ pixelsDest[destIndex1] = pixelsSrc[srcIndex1]; } else if( destIndex1 <= indexMax ){ pixelsDest[destIndex1] = Color.rgb( 0, 0, 0 ); } if( srcIndex2 <= indexMax && destIndex2 <= indexMax ){ pixelsDest[destIndex2] = pixelsSrc[srcIndex2]; } else if( destIndex2 <= indexMax ){ pixelsDest[destIndex2] = Color.rgb( 0, 0, 0 ); } if( srcIndex3 <= indexMax && destIndex3 <= indexMax ){ pixelsDest[destIndex2] = pixelsSrc[srcIndex2]; } else if( destIndex3 <= indexMax ){ pixelsDest[destIndex3] = Color.rgb( 0, 0, 0 ); } } else if( destIndex1 <= indexMax ){ pixelsDest[destIndex1] = Color.rgb( 0, 0, 0 ); } } } bitmap.setPixels( pixelsDest, 0, width, 0, 0, width, height ); return bitmap; }
オリジナル:
魚眼レンズ風:
変換式があるのですが、数学ができない自分にとっては理解不能。。。_| ̄|○
ディザリング(ベイヤー・渦巻・網点)
基本的には二値化処理ですが、こちらは乱数を使わずに一定のパターンに応じて処理を行います。
private Bitmap effectPatternDither( Bitmap bitmap, int patternFlg ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); int i, j; int[][] pattern; int[][] pattern1 = { { 0, 8, 2, 10 }, { 12, 4, 14, 6 }, { 3, 11, 1, 9 }, { 15, 7, 13, 5 } }; int[][] pattern2 = { { 6, 7, 8, 9 }, { 5, 0, 1, 10 }, { 4, 3, 2, 11 }, { 15, 14, 13, 12 } }; int[][] pattern3 = { { 11, 4, 6, 9 }, { 12, 0, 2, 14 }, { 7, 8, 10, 5 }, { 3, 15, 13, 1 } }; if( patternFlg == 2 ){ pattern = pattern2; } else if( patternFlg == 3 ){ pattern = pattern3; } else { pattern = pattern1; } for( i = 0; i < width; ++i ){ for( j = 0; j < height; ++j ){ int bitmapColor = pixels[( i + j * width )]; int r = Color.red( bitmapColor ); int g = Color.green( bitmapColor ); int b = Color.blue( bitmapColor ); r = r / 16; g = g / 16; b = b / 16; int x, y, z; y = ( r + g + b ) / 3; z = pattern[i % 4][j % 4]; if( y < z ){ x = 0; } else { x = 255; } int rr, gg, bb; rr = gg = bb = x; pixels[( i + j * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }
オリジナル:
二値化(白と黒):
ディザリング(ランダム)(違いは詳細で見てください):
ディザリング(ベイヤー)(違いは詳細で見てください):
ディザリング(渦巻)(違いは詳細で見てください):
ディザリング(網点)(違いは詳細で見てください):
ディザリング(ランダム)
基本的には二値化処理ですが、乱数を使って条件分岐の数値を変化させています。
private Bitmap effectRandomDither( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); Random random = new Random( ); for( int YY = 0; YY < width; ++YY ){ for( int XX = 0; XX < height; ++XX ){ int bitmapColor = pixels[( YY + XX * width )]; int rr = Color.red( bitmapColor ); int gg = Color.green( bitmapColor ); int bb = Color.blue( bitmapColor ); int Y = ( rr + gg + bb ) / 3; if( Y < random.nextInt( 256 ) ){ Y = 0; } else { Y = 255; } rr = Y; gg = Y; bb = Y; pixels[( YY + XX * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }
オリジナル:
二値化(白と黒):
ディザリング(ランダム)(違いは詳細で見てください):
疑似階調表現の一つしてディザリングがあるらしいのですが、この方法では処理結果が一定しなかったり条件によっては見づらくなる事もあるようです。
その欠点を改善した誤差拡散法というものがあるようですが、まだまだ勉強中。。。_| ̄|○
グレースケール
画像を白から黒までの明暗だけで表現するのがグレースケール。。。らしい。
private Bitmap efectGrayscale( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); for( int YY = 0; YY < width; ++YY ){ for( int XX = 0; XX < height; ++XX ){ int bitmapColor = pixels[( YY + XX * width )]; int rr = Color.red( bitmapColor ); int gg = Color.green( bitmapColor ); int bb = Color.blue( bitmapColor ); int Y = ( rr + gg + bb ) / 3; rr = Y; gg = Y; bb = Y; pixels[( YY + XX * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }
モノトーンと何が違うのか分かってませんが。_| ̄|○
セピア調
懐かしい雰囲気で有名?なセピア調に画像を加工。
本来であればR値はそのまま使うらしいけど、ちょっと赤っぽくなってしまうので少しR値を落としています。
private Bitmap effectSepiaTone( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); for( int YY = 0; YY < width; ++YY ){ for( int XX = 0; XX < height; ++XX ){ int bitmapColor = pixels[( YY + XX * width )]; int rr = Color.red( bitmapColor ); int gg = Color.green( bitmapColor ); int bb = Color.blue( bitmapColor ); float gray = ( rr * 0.298912f ) + ( gg * 0.586611f ) + ( bb * 0.114478f ); rr = gg = bb = (int)gray; rr *= 0.9f; gg *= 0.7f; bb *= 0.4f; pixels[( YY + XX * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }
ネガ
ネガというのは明るさを反転することらしい。
private Bitmap effectNegative( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); for( int YY = 0; YY < width; ++YY ){ for( int XX = 0; XX < height; ++XX ){ int bitmapColor = pixels[( YY + XX * width )]; int rr = Color.red( bitmapColor ); int gg = Color.green( bitmapColor ); int bb = Color.blue( bitmapColor ); rr = 255 - rr; gg = 255 - gg; bb = 255 - bb; pixels[( YY + XX * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }
ポスタリゼーション
使う色を限定する(階調数を落とす)という事らしい。
private Bitmap effectPosterization( Bitmap bitmap ){ if( bitmap == null ){ bitmap = BitmapFactory.decodeResource( getResources( ), R.drawable.original ).copy( Bitmap.Config.ARGB_8888, true ); } if( bitmap == null ){ return bitmap; } if( bitmap.isMutable( ) != true ){ bitmap = bitmap.copy( Bitmap.Config.ARGB_8888, true ); } int height = bitmap.getHeight( ); int width = bitmap.getWidth( ); int[] pixels = new int[( width * height )]; bitmap.getPixels( pixels, 0, width, 0, 0, width, height ); int step = 5; int[] stepArray = new int[step]; for( int X = 0; X < step; ++X ){ int rounds = (int)Math.round( 255.0f / ( step - 1 ) * X ); stepArray[X] = rounds; } for( int YY = 0; YY < width; ++YY ){ for( int XX = 0; XX < height; ++XX ){ int bitmapColor = pixels[( YY + XX * width )]; int r = Color.red( bitmapColor ); int g = Color.green( bitmapColor ); int b = Color.blue( bitmapColor ); int rr, rrr; int gg, ggg; int bb, bbb; rrr = (int)( Math.floor( r / ( 256 / step ) ) - 1 ); if( rrr < 0 ){ rrr = 0; } else if( rrr >= step ){ rrr = step = 1; } ggg = (int)( Math.floor( g / ( 256 / step ) ) - 1 ); if( ggg < 0 ){ ggg = 0; } else if( ggg >= step ){ ggg = step = 1; } bbb = (int)( Math.floor( b / ( 256 / step ) ) - 1 ); if( bbb < 0 ){ bbb = 0; } else if( bbb >= step ){ bbb = step = 1; } rr = stepArray[rrr]; gg = stepArray[ggg]; bb = stepArray[bbb]; pixels[( YY + XX * width )] = Color.rgb( rr, gg, bb ); } } bitmap.setPixels( pixels, 0, width, 0, 0, width, height ); return bitmap; }