Skin:
[NORMAL]
[BLUE] [DOS] [LIGHT]  / コピーするための表示 / 実行
このファイル: /home/web6047/www/cgi-bin/prj/_アルゴリズム/20180811-画像の指定色域の形状を得る/canvas.html
1 <!DOCTYPE html>
2 <head>
3 <meta content="text/html; charset=UTF-8" http-equiv="content-type">
4 <title>エッジ検出 プログラム</title>
5 <script>
6
7 console.clear();
8 console.log( "=============== script ==============" );
9 function con() { console.log( Array.prototype.join.call( arguments, " " ) ); }
10 function $( id ) { return document.getElementById( id ); }
11 var HereDocument = /\/\*\s*([^]*?)\s*\*\//;
12 // usage: var txt = ( function() { /*multiTXT*/ } ).toString().match( HereDocument )[ 1 ];
13
14 /*
15 【エッジ検出 プログラム】
16
17 関数は4個
18
19 getShapes() 画像(ImageData)と色を指定して、画像に含まれるその色の形をすべて取得
20 返り値は2次元配列。 2次元配列は [形][形が含む点] で、点はx,yを収めたオブジェクト。
21
22 _getShape() getShapes()から呼ばれる。開始位置から形状を取得して終了する。
23
24 onloadx() 上記2つの関数のテスト実行
25 draw() 上記2つの関数のテスト実行
26
27 */
28
29 function onloadx() {
30
31 canvasEL = $( "canvasELID" );
32 canvas = canvasEL.getContext( '2d' );
33 screenW = canvas.canvas.width;
34 screenH = canvas.canvas.height;
35
36 shape = new Array();
37
38
39 shapeSeek = -1;
40 shapesSeek = 0;
41 toggle = true;
42
43
44
45 //テスト画像について このonloadでプログラムが開始される
46 image = new Image();
47 image.onload = function() {
48
49 //ImageData取得のために描画
50 canvas.clearRect( 0, 0, screenW, screenH );
51 canvas.drawImage( image, 0, 0 );
52 var ID = canvas.getImageData( 0, 0, screenW, screenH ); //ID is ImageData
53
54 //この行がこのプログラムのポイントとなる行。
55 shapes = getShapes( ID, 0, 0, 0, 255, 120 ); //引数はImageDataと、RGBA各成分、色の許容量
56 //shapes = getShapes( ID, 79, 129, 189, 255, 25 );
57
58 draw( canvas );
59 };
60 image.src = "Sheet1.png";
61
62 //キー入力について
63 onkeydown = function( e ) {
64 switch( e.which ) {
65 case 37: toggle = false; shapeSeek-= e.target ? 1 : 10; break; //左キー
66 case 39: toggle = false; shapeSeek+= e.target ? 1 : 10; break; //上キー
67 case 38: toggle = true; shapesSeek--; shapeSeek = 0; break; //右キー
68 case 40: toggle = true; shapesSeek++; shapeSeek = 0; break; //下キー
69 case 32: toggle = true; shapesSeek++; shapeSeek = 0; break; //スペースキー
70 default:
71 console.log( e.which );
72 return true;
73 }
74
75 //check. 形状切り替え操作について
76 if( shapesSeek > shapes.length - 1 ) shapesSeek = 0;
77 if( shapesSeek < 0 ) shapesSeek = shapes.length - 1;
78 //check. 点打ち操作について
79 if( shapeSeek >= shapes[ shapesSeek ].length ) shapeSeek = shapes[ shapesSeek ].length - 1;
80 if( shapeSeek < 0 ) shapeSeek = 0;
81
82
83 console.log( "shape: ", shapesSeek, "/", shapes.length - 1, " ", shapeSeek, "/", shapes[ shapesSeek ].length - 1 );
84
85 draw( canvas );
86 return false;
87 }
88 }
89
90 function draw( cc ) {
91 //読み込んだ画像を描く
92 cc.clearRect( 0, 0, screenW, screenH );
93 cc.drawImage( image, 0, 0 );
94
95 //その上に認識した形状を描く
96 var shape = shapes[ shapesSeek ];
97 for( var i = 0; i < ( toggle ? shape.length : shapeSeek + 1 ); i++ ) {
98 var dot = shape[ i ];
99 cc.fillStyle = "red";
100 cc.fillRect( dot.x - 1, dot.y - 1, 2, 2 );
101 }
102 }
103
104 function getShapes( ID, R, G, B, A, tolerance ) {
105 var shapes = new Array();
106 var checkedAreas = new Array();
107
108 //内部関数 x,y座標の色は目的の色かどうかを調べる
109 //(この関数内のID(ImageData)とtoleranceはクロージャ(この関数内でいつまでも参照可))
110 var isOK = function( x, y ) {
111 var idx = ( y * ID.width + x ) * 4;
112 var dr = ID.data[ idx ];
113 var dg = ID.data[ idx + 1 ];
114 var db = ID.data[ idx + 2 ];
115 var da = ID.data[ idx + 3 ];
116 return da > A - tolerance
117 && da < A + tolerance //アルファ値は許容範囲か?
118 && dr > R - tolerance
119 && dr < R + tolerance //赤成分は許容範囲か? 以下同文
120 && dg > G - tolerance
121 && dg < G + tolerance
122 && db > B - tolerance
123 && db < B + tolerance;
124 };
125
126
127 //画像全体を走査
128 for( var y = 0; y < ID.height; y++ ) {
129 for( var x = 0; x < ID.width; x++ ) {
130
131 //check. 取得した領域はスキップ(高速化だが、大きなCという文字の湾部分に入り込んだ記号などが読めなくなる問題がある)
132 var ischecked = false;
133 for( var i = 0; i < checkedAreas.length; i++ ) {
134 var ca = checkedAreas[ i ];
135 if( x >= ca.sx && x <= ca.ex && y >= ca.sy && y <= ca.ey ) {
136 ischecked = true;
137 break;
138 }
139 }
140 if( ischecked ) continue;
141
142
143 //対象の色を見つけたら
144 if( isOK( x, y ) ) {
145 console.log( "start ", x, y );
146 var area = new Object();
147 shapes.push( _getShape( x, y, area, isOK ) );
148 checkedAreas.push( area );
149
150 }//if
151 }//for x
152 }//for y
153
154 //debug.
155 if( 0 ) { //これを1にすると、一時、認識したエリアを赤枠で表示
156 for( var i = 0; i < checkedAreas.length; i++ ) {
157 var ca = checkedAreas[ i ];
158 canvas.strokeStyle = "red";
159 canvas.strokeRect( ca.sx, ca.sy, ca.ex - ca.sx, ca.ey - ca.sy );
160 }
161 alert( "debug.. " + checkedAreas.length );
162 }
163
164 return shapes;
165 }
166
167 function _getShape( sx, sy, area, isOK ) { //isOK関数の中に対象の画像データが隠れている(それが良いというわけではない)
168
169 //check.(この「範囲」はgetShapes()でスキップする処理のためだけの目的で使用)
170 area.sx = Infinity;
171 area.sy = Infinity;
172 area.ex = 0;
173 area.ey = 0;
174
175 var result = new Array(); //返り値は認識した形状を形作るx,yの配列。
176
177 var dir = -1; //-1にすることで最初に右方向を調べることになる。0とかだとうまくいかない。
178 var cx = sx;
179 var cy = sy;
180
181 //ここで具体的に画像内を這いまわっている。
182 do {
183
184 //現在位置を収録
185 result.push( { x : cx, y : cy } );
186
187 //範囲を更新(この「範囲」はgetShapes()でスキップする処理のためだけの目的で使用)
188 area.sx = Math.min( area.sx, cx );
189 area.sy = Math.min( area.sy, cy );
190 area.ex = Math.max( area.ex, cx );
191 area.ey = Math.max( area.ey, cy );
192
193 //進行可能な方向を調べる
194 for( var i = dir - 1; i < dir + 3; i++ ) { //今向いている方向の左手側から時計回りに4方向を調べる、という意味になっている
195 var i2 = ( 4 + i ) % 4; //%4は3の次を0にするため。4+は負値を直すため。
196 var tmpX = cx + ( i2 == 2 ) - ( i2 == 0 );
197 var tmpY = cy + ( i2 == 3 ) - ( i2 == 1 );
198
199 if( isOK( tmpX, tmpY ) ) {
200 dir = i2;
201 cx = tmpX;
202 cy = tmpY;
203 break;
204 }
205 }//for
206
207 } while( cx != sx || cy != sy ); //始点に戻ったら終了。
208
209 console.log( "end.", cx, cy, dir );
210
211 return result;
212 }
213 </script>
214 <style>
215 </style>
216 </head>
217 <body onload="onloadx();" style="
218 background-color : lightgray;
219 ">
220 <div style="text-align:center;">
221 Edge detection.
222 </div>
223 <canvas id="canvasELID" width="512" height="448" style="
224 display : block;
225 margin : auto;
226 background-color : white;
227 border : solid 1px black;
228
229
230 ">There is no canvas.</canvas>
231 <div style="text-align:center;">
232 [space] : <a href="javascript:onkeydown({which:32});void(0);">change focus</a>
233 / [arrow left, right] : dot <a href="javascript:onkeydown({which:39});void(0);">go</a>,
234 <a href="javascript:onkeydown({which:37});void(0);">back</a>
235 </div>
236 </body>
237 </html>