清明節の白黒効果=>色彩行列のアルゴリズムについて話します.

10146 ワード

昨日各大平台で通知を受けました.トップページはモノクロの効果で展示する必要があります.高級ブラウザには簡単な属性があります.全体設定すれば、満足できます.
-webkit-filter: grayscale(100%);filter: grayscale(100%);
低レベルブラウザでは、例えばgrayscale.jsのようなサードパーティ・プラグインを介して実現することができる.
このようなプラグインの原理は、簡単には再帰的なDOM構造であり、ノードのタイプを判断し、テキストであれば直接にその色の値を変更し、ピクチャであれば、canvasによって色の値を変更する.
どのように写真の色を変えるかというと、今日私たちが話しに来た色行列です.
実際には、各ピクセル値を多次元マトリクスに乗せれば、新しいピクセル値(rgba)が得られます.
matrix!:Array = [];

RGBA = [ R, G, B, A ]

matrix =[ 1, 0, 0, 0, 0,
          0, 1, 0, 0, 0,
          0, 0, 1, 0, 0,
          0, 0, 0, 1, 0 ] //    

       = RGBA * matrix = [
                matrix[0]*R + matrix[1]*G + matrix[2]*B + matrix[3]*A + matrix[4] // R  
                matrix[5]*R + matrix[6]*G + matrix[7]*B + matrix[8]*A + matrix[9] // G  
                matrix[10]*R + matrix[11]*G + matrix[12]*B + matrix[13]*A + matrix[14] // B  
                matrix[15]*R + matrix[16]*G + matrix[17]*B + matrix[18]*A + matrix[19] // A  
             ]
matirixは20項目からなる配列で、4 x 5色変換に適しています.
redチャネルの値:(1,0,0,0,0)Rチャネルの乗数は1(完全に保持)であり、他のチャネルの乗数は0であり、(他のチャネルの色を加えない)色オフセット量offは0である.
greenチャネルの値:(0,  1,  0,  0,  0)Gチャネルの乗数は1(完全に保留)であり、他のチャネルの乗数は0(他のチャネルの色を入れない)であり、色オフセット量offは0であることを示している.
ブルーチャンネルの値:(0、  0,  1,  0,  0)は、Bチャネルの乗数は1(完全に保留)であり、他のチャネルの乗数は0(他のチャネルの色を入れない)であり、色オフセット量offは0であることを示している.
アルファチャネルの値:(0,  0,  0,  1,  0)Aチャネルの乗数は1(完全に保留)であり、他のチャネルの乗数は0(他のチャネルの色を入れない)であり、色オフセット量offは0であることを示している.
4 x 5  4行5列は4列(RGBBA)と知っていますが、5列目(Nと略称)は色の明るさの調整です.
1,0,0,0,N
0,1,0,0,N
0,0,1,0,N
0,0,0,1,0

N=>      -255 255,       RGB            
例えば、値がrgba(200,100,50,1)の色が欲しいなら、赤い通路の色だけを残します.私たちはmatrixを調整して次のように計算します.
[ 200, 100, 50, 1 ] * [ 1, 0, 0, 0, 0,
                        0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0,
                        0, 0, 0, 1, 0 ] = [
                            1*200 + 0*100 + 0*50 + 0*1 + 0,
                            0*200 + 0*100 + 0*50 + 0*1 +0,
                            0*200 + 0*100 + 0*50 + 0*1 +0,
                            0*200 + 0*100 + 0*50 + 1*1 +0,
                        ] = [ 200, 0, 0, 1 ]
色を反転
[ 200, 100, 50, 1 ] * [ -1, 0, 0, 0, 255,
                        0, -1, 0, 0, 255,
                        0, 0, -1, 0, 255,
                        0, 0, 0, 1, 0 ] = [
                            -1*200 + 0*100 + 0*50 + 0*1 + 255,
                            0*200 + -1*100 + 0*50 + 0*1 +255
                            0*200 + 0*100 + -1*50 + 0*1 +255,
                            0*200 + 0*100 + 0*50 + 1*1 +0,
                        ] = [ 206, 206, 206, 1]
昨日の白黒はどうやって実現しましたか?色は色を消して、同じマトリックスアルゴリズムですが、チャネル値は上と同じではありません.
matrix = [ 0.3086, 0.6094, 0.0820, 0, 0
            0.3086, 0.6094, 0.0820, 0, 0
            0.3086, 0.6094, 0.0820, 0, 0
            0 , 0 , 0, 1, 0 ]
RGB 3チャンネルのカラー情報を同じに設定してください.つまり、R=G=Bは画像が灰色になり、画像の明るさが変わらないようにするために、同じチャンネルのR+G+B=1はなぜこの3つの小数点なのか不思議に思う人が多いです.実はRGBを1つの割合で均等に分けました.3:6:1、つまり:0.3686、0.6904、0.0820
ここを見れば、画像の色を変える鍵はマトリックス乗算であり、異なる多次元マトリックスの元の値を通じて、異なる効果を達成することが分かるはずです.私たちが見たマイクロクレジット画像フィルタと社交プラットフォームinsの画像フィルタも、マルチ次元マトリックスアルゴリズムによって画像フィルタを実現します.
これを使って最終的にはどのような効果が得られますか?
以下はそれぞれの効果によってパッケージされた初期行列値です.(上で述べたように、同じチャンネルのRGB加算は1=>R+G+B=1に等しくなければなりません.)
desaturate: function() {
			return this.add([
						FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, 0, 
						FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, 0, 
						FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, 0, 
						0, 0, 0, 1, 0
					]);
		},
		//                         
		average: function( r, g, b ) {
			if ( r === undefined ) r = 0.3333;
			if ( g === undefined ) g = 0.3333;
			if ( b === undefined ) b = 0.3334;
			
			return this.add([
					r, g, b, 0, 0, 
					r, g, b, 0, 0, 
					r, g, b, 0, 0, 
					0, 0, 0, 1, 0
				]);
		},
		
		//                
		brightness: function( r, g, b ) {
			if ( g === undefined )  g = r;
			if ( b === undefined )  b = r;
			return this.add([
					1, 0, 0, 0, r, 
					0, 1, 0, 0, g, 
					0, 0, 1, 0, b, 
					0, 0, 0, 1, 0
				]);
		},
		
		
		
		//  
		colorize: function( rgb, alpha ) {
			var r, g, b, inv_alpha;
			if ( alpha === undefined ) alpha = 1;
			//var alpha = alpha ? 0 : 1;
			r = (((rgb >> 16) & 255) * 0.0039215686274509803921568627451);  // / 255
			g = (((rgb >> 8) & 255) * 0.0039215686274509803921568627451);  // / 255
			b = ((rgb & 255) * 0.0039215686274509803921568627451);  // / 255
			inv_alpha = 1 - alpha;
			
			//console.log((rgb >> 8).toString(2))
			//console.log((255).toString(2))
			//console.log(((rgb >> 8) & 255).toString(2))
			
			//console.log((inv_alpha + ((alpha * r) * FILTER.LUMA[0])), ((alpha * r) * FILTER.LUMA[1]), ((alpha * r) * FILTER.LUMA[2]), 0, 0)
			//console.log(((alpha * g) * FILTER.LUMA[0]), (inv_alpha + ((alpha * g) * FILTER.LUMA[1])), ((alpha * g) * FILTER.LUMA[2]), 0, 0)
			//console.log(((alpha * b) * FILTER.LUMA[0]), ((alpha * b) * FILTER.LUMA[1]), (inv_alpha + ((alpha * b) * FILTER.LUMA[2])), 0, 0)
	
			return this.add([
						(inv_alpha + ((alpha * r) * FILTER.LUMA[0])), ((alpha * r) * FILTER.LUMA[1]), ((alpha * r) * FILTER.LUMA[2]), 0, 0, 
						((alpha * g) * FILTER.LUMA[0]), (inv_alpha + ((alpha * g) * FILTER.LUMA[1])), ((alpha * g) * FILTER.LUMA[2]), 0, 0, 
						((alpha * b) * FILTER.LUMA[0]), ((alpha * b) * FILTER.LUMA[1]), (inv_alpha + ((alpha * b) * FILTER.LUMA[2])), 0, 0, 
							0, 0, 0, 1, 0
						]);
		},
		
		//  
		invert: function( ) {
			return this.add([
					-1, 0,  0, 0, 255,
					0, -1,  0, 0, 255,
					0,  0, -1, 0, 255,
					0,  0,  0, 1,   0
				]);
		},
		
		invertRed: function( ) {
			return this.add([
					-1, 0,  0, 0, 255,
					0,  1,  0, 0, 255,
					0,  0,  1, 0, 255,
					0,  0,  0, 1,   0
				]);
		},
		
		invertGreen: function( ) {
			return this.add([
					1,  0,  0, 0, 255,
					0,  -1, 0, 0, 255,
					0,  0,  1, 0, 255,
					0,  0,  0, 1,   0
				]);
		},
		
		invertBlue: function( ) {
			return this.add([
					1,  0,  0, 0, 255,
					0,  1,  0, 0, 255,
					0,  0, -1, 0, 255,
					0,  0,  0, 1,   0
				]);
		},
		
		//alpha   
		invertAlpha: function( ) {
			return this.add([
					1,  0,  0, 0, 0,
					0,  1,  0, 0, 0,
					0,  0,  1, 0, 0,
					0,  0,  0, -1, 255
				]);
		},
		
		//   
		saturate: function( s ) {
			
			var sInv, irlum, iglum, iblum;
			sInv = (1 - s);
			irlum = (sInv * FILTER.LUMA[0]);
			iglum = (sInv * FILTER.LUMA[1]);
			iblum = (sInv * FILTER.LUMA[2]);
			
			return this.add([
					(irlum + s), iglum, iblum, 0, 0, 
					irlum, (iglum + s), iblum, 0, 0, 
					irlum, iglum, (iblum + s), 0, 0, 
					0, 0, 0, 1, 0
				]);
		},
		
		//   
		contrast: function( r, g, b ) {
			if ( g === undefined )  g = r;
			if ( b === undefined )  b = r;
			r += 1.0; g += 1.0; b += 1.0;
			return this.add([
					r, 0, 0, 0, (128 * (1 - r)), 
					0, g, 0, 0, (128 * (1 - g)), 
					0, 0, b, 0, (128 * (1 - b)), 
					0, 0, 0, 1, 0
				]);
		},
		//       
		quickContrastCorrection: function( contrast ) {
			if ( contrast === undefined ) contrast = 1.2;
			return this.add([
				contrast, 0, 0, 0, 0, 
				0, contrast, 0, 0, 0, 
				0, 0, contrast, 0, 0, 
				0, 0, 0, 1, 0
				]);
		},
		
		//        0-360
		adjustHue: function( degrees ) {
			degrees *= FILTER.CONSTANTS.toRad;
			var cos = Math.cos(degrees), sin = Math.sin(degrees);
			
			return this.add([
					((FILTER.LUMA[0] + (cos * (1 - FILTER.LUMA[0]))) + (sin * -(FILTER.LUMA[0]))), ((FILTER.LUMA[1] + (cos * -(FILTER.LUMA[1]))) + (sin * -(FILTER.LUMA[1]))), ((FILTER.LUMA[2] + (cos * -(FILTER.LUMA[2]))) + (sin * (1 - FILTER.LUMA[2]))), 0, 0, 
					((FILTER.LUMA[0] + (cos * -(FILTER.LUMA[0]))) + (sin * 0.143)), ((FILTER.LUMA[1] + (cos * (1 - FILTER.LUMA[1]))) + (sin * 0.14)), ((FILTER.LUMA[2] + (cos * -(FILTER.LUMA[2]))) + (sin * -0.283)), 0, 0, 
					((FILTER.LUMA[0] + (cos * -(FILTER.LUMA[0]))) + (sin * -((1 - FILTER.LUMA[0])))), ((FILTER.LUMA[1] + (cos * -(FILTER.LUMA[1]))) + (sin * FILTER.LUMA[1])), ((FILTER.LUMA[2] + (cos * (1 - FILTER.LUMA[2]))) + (sin * FILTER.LUMA[2])), 0, 0, 
					0, 0, 0, 1, 0
				]);
		},
		
		
		
		//sepia           。
		sepia: function( amount ) {
			if ( amount === undefined ) amount = 0.5;
			if ( amount > 1 ) amount = 1;
			else if ( amount < 0 ) amount = 0;
			return this.add([
				1.0 - (0.607 * amount), 0.769 * amount, 0.189 * amount, 0, 0, 
				0.349 * amount, 1.0 - (0.314 * amount), 0.168 * amount, 0, 0, 
				0.272 * amount, 0.534 * amount, 1.0 - (0.869 * amount), 0, 0, 
				0, 0, 0, 1, 0
			]);
		},
		
		//sepia2            。
		sepia2: function( amount ) {
			if ( amount === undefined ) amount = 10;
			if ( amount > 100 ) amount = 100;
			amount *= 2.55;
			return this.add([
				FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, 40, 
				FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, 20, 
				FILTER.LUMA[0], FILTER.LUMA[1], FILTER.LUMA[2], 0, -amount, 
				0, 0, 0, 1, 0
			]);
		},
		//    
		threshold: function( threshold, factor ) {
			if ( factor === undefined )  factor = 256;
			
			return this.add([
					(FILTER.LUMA[0] * factor), (FILTER.LUMA[1] * factor), (FILTER.LUMA[2] * factor), 0, (-(factor-1) * threshold), 
					(FILTER.LUMA[0] * factor), (FILTER.LUMA[1] * factor), (FILTER.LUMA[2] * factor), 0, (-(factor-1) * threshold), 
					(FILTER.LUMA[0] * factor), (FILTER.LUMA[1] * factor), (FILTER.LUMA[2] * factor), 0, (-(factor-1) * threshold), 
					0, 0, 0, 1, 0
				]);
		},
		
		
		//       
		threshold_rgb: function( threshold, factor ) {
			if ( factor === undefined )  factor = 256;
			
			return this.add([
					factor, 0, 0, 0, (-(factor-1) * threshold), 
					0, factor, 0, 0, (-(factor-1) * threshold), 
					0,  0, factor, 0, (-(factor-1) * threshold), 
					0, 0, 0, 1, 0
				]);
		},
		
		/*threshold_alpha: function( threshold, factor ) {
			if ( threshold === undefined )  threshold = 0.5;
			if ( factor === undefined ) factor = 256;
			
			return this.add([
					1, 0, 0, 0, 0, 
					0, 1, 0, 0, 0, 
					0, 0, 1, 0, 0, 
					0, 0, 0, factor, (-factor * threshold)
				]);
		},*/