├── .gitignore ├── License ├── README.md ├── module ├── 00_develop.js ├── core.js ├── highgui.js ├── imgcodecs.js ├── imgproc.js ├── ml.js └── test.js └── opencv.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | haar* -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Kei Sakiyama 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | 以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。 12 | 13 | 上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。 14 | 15 | ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、それに限定されるものではありません。 作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、損害、その他の義務について何らの責任も負わないものとします。 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OpenCVjs 2 | 3 | OpenCVjsは画像処理ライブラリのOpenCVをjavascriptに移植したライブラリです。 4 | 5 | このライブラリだけで動作可能でありjavascriptだけで実装されているので、ダウンロードすればそのままブラウザ上で実行できます。 6 | メソッドは基本的にOpenCV1.0系と同様の名前と機能となっており、使い方の説明はアメーバブログ「画像処理だけで飯が食えるかっ!?」に記しています。 7 | 8 | 初期設定としてOpenCVjs/opencv.js内のOPENCVJS_PATHの値を同ディレクトリのパスにして下さい 9 | それからOpenCVjs/opencv.jsを読み込んで下さい -------------------------------------------------------------------------------- /module/00_develop.js: -------------------------------------------------------------------------------- 1 | //-------------------定数-------------------------- 2 | //インペイントの種類 3 | var CV_INPAINT = { 4 | NS: 0, 5 | TELEA: 1 6 | } 7 | 8 | 9 | //------------------メソッド------------------------ 10 | 11 | //行列の二重対角化 12 | //入力 13 | //mat CvMat型 対角化する行列 14 | //eps double型 計算精度 デフォルト CV_DEF_EPS 15 | function cvmDoubleDiagonalization(mat, eps){ 16 | var rtn = null; 17 | try{ 18 | //バリデーション 19 | if(cvUndefinedOrNull(mat)) 20 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 21 | 22 | //デフォルト値 23 | if(cvUndefinedOrNull(eps)) eps = CV_DEF_EPS; 24 | 25 | //--内部で使う処理を関数化-- 26 | //行列から指定した範囲の行列を抜き出す 27 | function partMatrix(mat, sx, sy, ex, ey){ 28 | 29 | var mcols = ex - sx; 30 | var mrows = ey - sy; 31 | 32 | var mar = cvCreateMat(mrows, mcols); 33 | for(var i = 0 ; i < mar.rows ; i++){ 34 | for(var j = 0 ; j < mar.cols ; j++){ 35 | mar.vals[j + i * mar.cols] = mat.vals[sx + j + (sy + i) * mat.cols]; 36 | } 37 | } 38 | 39 | return mar; 40 | } 41 | //行列の指定された範囲内のうちの要素の最大値とその座標を返す 42 | function maxAbsAndXY(ar, sx, sy, ex, ey){ 43 | //デフォルト値 44 | if(cvUndefinedOrNull(sx)) sx = 0; 45 | if(cvUndefinedOrNull(sy)) sy = 0; 46 | if(cvUndefinedOrNull(ex)) ex = ar.cols; 47 | if(cvUndefinedOrNull(ey)) ey = ar.rows; 48 | 49 | var max = Math.abs(ar.vals[sx + sy * ar.cols]); 50 | var mx = sx; 51 | var my = sy; 52 | for(var y = sy ; y < ey ; y++){ 53 | for(var x = sx ; x < ex ; x++){ 54 | var tmp = Math.abs(ar.vals[x + y * ar.cols]); 55 | if(max < tmp){ 56 | max = tmp; 57 | mx = x; 58 | my = y; 59 | } 60 | } 61 | } 62 | 63 | return [max, mx, my]; 64 | } 65 | 66 | //行列の指定した列ベクトルのノルムの二乗 67 | function norm2MatrixCol(mat, col, start, end){ 68 | //デフォルト値 69 | if(cvUndefinedOrNull(start)) start = 0; 70 | if(cvUndefinedOrNull(end)) end = mat.rows; 71 | 72 | var vec = cvCreateMat(end - start, 1); 73 | for(var i = 0 ; i < vec.rows ; i++){ 74 | vec.vals[i] = mat.vals[col + (i + start) * mat.cols]; 75 | } 76 | 77 | return cvmNorm(vec, null, CV_NORM.L2Square); 78 | } 79 | 80 | //行列の指定した行ベクトルのノルムの二乗 81 | function norm2MatrixRow(mat, row, start, end){ 82 | 83 | //デフォルト値 84 | if(cvUndefinedOrNull(start)) start = 0; 85 | if(cvUndefinedOrNull(end)) end = mat.rows; 86 | 87 | var vec = cvCreateMat(end - start, 1); 88 | for(var i = 0 ; i < vec.rows ; i++){ 89 | vec.vals[i] = mat.vals[i + start + row * mat.cols]; 90 | } 91 | 92 | return cvmNorm(vec, null, CV_NORM.L2Square); 93 | } 94 | 95 | //行列の列ベクトルと縦ベクトルのhouseholder変換行列 96 | function householderMatColVec(mat, col, vec){ 97 | var rtn = null; 98 | try{ 99 | if(mat.rows != vec.rows) 100 | throw "matとvec" + ERROR.DIFFERENT_LENGTH; 101 | 102 | var matV = cvCreateMat(mat.rows, 1); 103 | for(var i = 0 ; i < matV.rows ; i++){ 104 | matV.vals[i] = mat.vals[col + i * mat.cols]; 105 | } 106 | 107 | rtn = cvmHouseHolder(matV, vec); 108 | } 109 | catch(ex){ 110 | alert("householderMatColVec : " + ex); 111 | } 112 | return rtn; 113 | } 114 | 115 | //行列の行ベクトルと横ベクトルのhouseholder変換行列(ただし1次元配列として返す) 116 | function householderMatRowVec(mat, row, vec){ 117 | var rtn = null; 118 | try{ 119 | if(mat.cols != vec.cols) 120 | throw "matとvec" + ERROR.DIFFERENT_LENGTH; 121 | 122 | var matV = cvCreateMat(1, mat.cols); 123 | var rw = row * mat.cols; 124 | for(var i = 0 ; i < matV.cols ; i++){ 125 | matV.vals[i] = mat.vals[i + rw]; 126 | } 127 | 128 | rtn = cvmHouseHolder(matV, vec); 129 | } 130 | catch(ex){ 131 | alert("householderMatRowVec : " + ex); 132 | } 133 | 134 | return rtn; 135 | } 136 | //---------------------- 137 | 138 | //matのコピー 139 | var rtn = cvmCopy(mat); 140 | 141 | var sx = sy = 0; 142 | while(true){ 143 | 144 | //ar^(times)段階目の対角化を行う小行列を取得 145 | var mar = partMatrix(rtn, sx, sy, rtn.cols, rtn.rows); 146 | var mwidth = rtn.cols - sx; 147 | var mheight = rtn.rows - sy; 148 | 149 | var maxVXY; 150 | var vec; 151 | var hhMat; 152 | 153 | //step6に到達するまでループ 基本はstep1 ~ 6と進む 154 | var step = 1; 155 | while(step != -1){ 156 | switch(step){ 157 | case 1://ar^(times)の要素で絶対値が最大とるなる要素を探す。その値がeps以下なら二重対角化終了 158 | 159 | maxVXY = maxAbsAndXY(mar, mwidth); 160 | if(maxVXY[0] < eps){ 161 | dWrite(0, "finish"); 162 | step = -1; //二重対角化終了 163 | break; 164 | } 165 | 166 | step = 2; 167 | 168 | break; 169 | 170 | case 2://絶対値最大の要素を含む行とar^(times)の第1行を入れ替える 171 | for(var i = 0 ; i < mar.cols ; i++){ 172 | var tmp = mar.vals[i]; 173 | mar.vals[i] = mar.vals[i + maxVXY[2] * mar.cols]; 174 | mar.vals[i + maxVXY[2] * mar.cols] = tmp; 175 | } 176 | 177 | step = 3; 178 | 179 | break; 180 | 181 | case 3://ar^(times)の第1列において、絶対値が最大となる要素を探す。その値がeps以下ならd_times=0とおきstep6へ 182 | maxVXY = maxAbsAndXY(mar, 0, 0, 1, mheight); 183 | 184 | if(maxVXY[0] > eps){ 185 | step = 4; 186 | } 187 | else{ 188 | mar[0] = 0; 189 | step = 6; 190 | } 191 | 192 | break; 193 | 194 | case 4://ar^(times)の第1列の第2項以下を0とするようなハウスホルダー変換を左からar^(times)に行う 195 | vec = cvCreateMat(mheight, 1); 196 | vec.vals[0] = Math.sqrt(norm2MatrixCol(mar, 0)); 197 | for(var i = 1 ; i < vec.rows ; vec.vals[i++] = 0); 198 | 199 | hhMat = householderMatColVec(mar, 0, vec); 200 | 201 | mar = cvmMul(hhMat, mar); 202 | 203 | //最後の2行2列の場合は列方向だけハウスホルダー変換し、対角化が終了となる 204 | step = sx == mat.cols - 2 ? -1 : 5; 205 | 206 | break; 207 | 208 | case 5://ar^(times)の第1行において第2項以降で絶対値が最大となる要素を探す。その値がeps以下なら第1行第2項を0とおきstep7へ 209 | 210 | maxVXY = maxAbsAndXY(mar, 1, 0, mwidth, 1); 211 | 212 | if(maxVXY[0] > eps) step = 6; 213 | else{ 214 | mar.vals[1] = 0; 215 | step = -1; 216 | } 217 | 218 | break; 219 | 220 | case 6://ar^(times)の第1行の第3項以降を0とするようなハウスホルダー変換を右から行う 221 | vec = cvCreateMat(1, mwidth); 222 | vec.vals[0] = mar.vals[0]; 223 | vec.vals[1] = Math.sqrt(norm2MatrixRow(mar, 0, 1, mwidth)); 224 | for(var i = 2 ; i < vec.cols ; vec.vals[i++] = 0); 225 | 226 | hhMat = householderMatRowVec(mar, 0, vec); 227 | 228 | mar = cvmMul(mar, hhMat); 229 | 230 | step = -1; 231 | 232 | break; 233 | default://ループ用パラメータ更新 234 | throw "ありえないstepが実行されました"; 235 | break; 236 | } 237 | } 238 | 239 | //コピー 240 | for(var i = 0 ; i < mheight ; i++){ 241 | for(var j = 0 ; j < mwidth ; j++){ 242 | rtn.vals[sx + j + (sy + i) * rtn.cols] = mar.vals[j + i * mwidth]; 243 | } 244 | } 245 | 246 | sx++; 247 | sy++; 248 | if(sx == mat.cols - 1 || sy == mat.rows - 1){ //終了条件 249 | break; 250 | } 251 | } 252 | } 253 | catch(ex){ 254 | alert("cvmDoubleDiagonalization : " + ex); 255 | } 256 | 257 | return rtn; 258 | } 259 | 260 | 261 | 262 | 263 | 264 | 265 | function cvKMeans2(samples, cluster_count, labels, termcrit){ 266 | try{ 267 | if(cvUndefinedOrNull(samples) || cvUndefinedOrNull(cluster_count) || cvUndefinedOrNull(labels) 268 | || cvUndefinedOrNull(termcrit)) 269 | throw "samples or cluster_count or labels or termcrit " + ERROR.IS_UNDEFINED_OR_NULL; 270 | 271 | function clustering(samples, clusters, labels) 272 | { 273 | for(var i = 0 ; i < samples.height ; i++){ 274 | for(var j = 0 ; j < samples.width; j++){ 275 | var ji = (j + i * samples.width) * CHANNELS; 276 | var c1 = samples.RGBA[ji]; 277 | var c2 = samples.RGBA[1 + ji]; 278 | var c3 = samples.RGBA[2 + ji]; 279 | 280 | var disC1 = c1 - clusters.RGBA[0]; 281 | var disC2 = c2 - clusters.RGBA[1]; 282 | var disC3 = c3 - clusters.RGBA[2]; 283 | 284 | var dis = disC1 * disC1 + disC2 * disC2 + disC3 * disC3; 285 | 286 | for(var cnum = 1 ; cnum < clusters.width; cnum++){ 287 | 288 | } 289 | } 290 | } 291 | } 292 | } 293 | catch(ex){ 294 | alert("cvKMeans2 : " + ex); 295 | } 296 | } 297 | 298 | function cvInPaint(src, mask, dst, inpaintRadius, flags){ 299 | try{ 300 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(mask) || cvUndefinedOrNull(dst) 301 | || cvUndefinedOrNull(inpaintRadius)) 302 | throw "src or mask or dst or inpaintRadius " + ERROR.IS_UNDEFINED_OR_NULL; 303 | if(src.width != dst.width || src.height != dst.height || 304 | mask.width != dst.width || mask.height != dst.height) 305 | throw "src or mask or dst " + ERROR.DIFFERENT_SIZE; 306 | 307 | if(flags != CV_INPAINT.TELEA) 308 | throw "flagsは現在CV_INPAINT.TELENAしかサポートしていません"; 309 | 310 | function cvInPaintOneLoop(src, mask, dst, inpaintRadius, flags){ 311 | 312 | // -- maskのエッジ探索 -- 313 | var edge = new cvCreateImage(src.width, src.height); 314 | cvZero(edge); 315 | for(var i = 0 ; i < edge.height ; i++){ 316 | if(i != 0 && i != edge.height - 1){ 317 | for(var j = 0 ; j < edge.width ; j++){ 318 | var v = 0; 319 | if(j != 0 && j != edge.width - 1){ 320 | //8近傍チェック 321 | for(var y = -1 ; y <= 1 ; y++){ 322 | for(var x = -1 ; x <= 1 ; x++){ 323 | if(mask.RGBA[(j + x + (i + y) * mask.width) * CHANNELS] == 0){ 324 | v = 255; 325 | break; 326 | } 327 | } 328 | if(v != 0) break; 329 | } 330 | } 331 | edge.RGBA[(j + i * edge.width) * CHANNELS] = v; 332 | } 333 | } 334 | else{ 335 | for(var j = 0 ; j < edge.width ; j++){ 336 | edge.RGBA[(j + i * edge.width) * CHANNELS] = 255; 337 | } 338 | } 339 | } 340 | 341 | // -- 輝度勾配 -- 342 | gImage = cvCreateImage(src.width, src.height); 343 | cvZero(gImage); 344 | for(var i = 0 ; i < gImage.height ; i++){ 345 | for(var j = 0 ; j < gImage.width ; j++){ 346 | if(edge.RGBA[(j + i * edge.width) * CHANNNELS] != 0){ 347 | for(var c = 0 ; c < 3 ; c++){ 348 | var dx = src.RGBA[(j + 1 + i * src.width) * CHANNNELS] - src.RGBA[(j - 1 + i * src.width) * CHANNNELS]; 349 | var dx = src.RGBA[(j + (i + 1) * src.width) * CHANNNELS] - src.RGBA[(j + (i - 1) * src.width) * CHANNNELS]; 350 | } 351 | } 352 | } 353 | } 354 | 355 | switch(flags){ 356 | case CV_INPAINT.NS: 357 | break; 358 | default: 359 | break; 360 | } 361 | } 362 | } 363 | catch(ex){ 364 | alert("cvInPaint : " + ex); 365 | } 366 | } 367 | 368 | //ハフ変換 369 | //入力 370 | //src IplImage型 GRAY表色系を想定(RGB表色系ならRで実行される) 371 | //method CV_HOUGH型 ハフ変換の種類 372 | //rho 少数 距離解像度 1ピクセルあたりの単位 373 | //theta 少数 角度解像度 ラジアン単位 374 | //threshold 整数 対応する投票数がこの値より大きい場合のみ抽出された直線が返される 375 | //param1 少数 各手法に応じたパラメータ 解説参照 376 | //param2 少数 各手法に応じたパラメータ 解説参照 377 | //出力 378 | //[ラインの数][ラインの情報]の二次元配列が返る 379 | //[X][0]にrhoの値 380 | //[X][1]にthetaの値 381 | //解説 382 | //CV_HOUGH.STANDARDの場合 383 | // param1,param2共に使用しない(0) 384 | //CV_HOUGH.PROBABILISTICの場合 385 | // param1は最小の線の長さ使用しない(0) 386 | // param2は同一線として扱う線分の最大間隔 387 | //CV_HOUGH.MULTI_SCALEの場合 388 | // param1はrhoの序数(荒い距離はrho,詳細な距離ではrho/param1) 389 | // param2はthetaの序数 (荒い角度はtheta,詳細な角度ではtheta/param2) 390 | //http://codezine.jp/article/detail/153 391 | function cvHoughLines2(src, method, rho, theta, threshold, param1, param2){ 392 | var rtn = null; 393 | try{ 394 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(method) || 395 | cvUndefinedOrNull(rho) || cvUndefinedOrNull(theta) || cvUndefinedOrNull(threshold)) 396 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 397 | 398 | if(method != CV_HOUGH.STANDARD) 399 | throw "methodは現在CV_HOUGH.STANDARDしかサポートしていません"; 400 | 401 | if(cvUndefinedOrNull(param1)) param1 = 0; 402 | if(cvUndefinedOrNull(param2)) param2 = 0; 403 | 404 | //--------------------------------------- 405 | //-- 初期化 -- 406 | //--------------------------------------- 407 | var rtn = new Array(); 408 | var thetaMax = Math.floor(Math.PI/theta); 409 | var sn = new Array(thetaMax); //サインカーブ配列 410 | var cs = new Array(thetaMax);//コサインカーブ配列 411 | var diagonal = new Array(src.height);//半径計算用斜線長テーブル 412 | 413 | var counter = new Array(thetaMax);//直線検出用頻度カウンタ 414 | var rhoMax = Math.floor(Math.sqrt(src.width * src.width + src.height * src.height) + 0.5); 415 | for(var i = 0 ; i < counter.length ; i++){ 416 | counter[i] = new Array(2 * rhoMax); 417 | for(var j = 0 ; j < counter[i].length ; j++){ 418 | counter[i][j] = 0; 419 | } 420 | } 421 | 422 | //三角関数テーブルを作成 423 | for(var i = 0 ; i < sn.length ; i++){ 424 | sn[i] = Math.sin(i * theta); 425 | cs[i] = Math.cos(i * theta); 426 | } 427 | 428 | 429 | switch(method){ 430 | 431 | case CV_HOUGH.STANDARD: 432 | 433 | for(var i = 0 ; i < src.height ; i++){ 434 | var is = i * src.width * CHANNELS; 435 | var js = 0; 436 | for(var j = 0 ; j < src.width ; j++){ 437 | if(src.RGBA[js + is] == 255){ 438 | for(var t = 0 ; t < thetaMax; t++){ 439 | r = Math.floor(j * cs[t] + i * sn[t] + 0.5); 440 | counter[t][r + rhoMax]++; 441 | } 442 | } 443 | js += CHANNELS; 444 | } 445 | } 446 | 447 | break; 448 | 449 | case CV_HOUGH.PROBABILISTIC: 450 | break; 451 | case CV_HOUGH.MULTI_SCALE: 452 | break; 453 | } 454 | 455 | var num = 0; 456 | for(var t = 0 ; t < counter.length ; t++){ 457 | for(var r = 0 ; r < counter[t].length ; r++){ 458 | if(counter[t][r] > threshold){ 459 | rtn[num] = new Array(2); 460 | rtn[num][0] = r - rhoMax; 461 | rtn[num][1] = t; 462 | num++; 463 | } 464 | } 465 | } 466 | } 467 | catch(ex){ 468 | alert("cvHoughLines2 : " + ex); 469 | } 470 | 471 | return rtn; 472 | } 473 | 474 | -------------------------------------------------------------------------------- /module/core.js: -------------------------------------------------------------------------------- 1 | //------------------データ型------------------------ 2 | //canvasのRGBA値は0から255の値しかもてないため専用の画像データ型を用意 3 | var IplImage = function(){ 4 | this.width = 0; 5 | this.height = 0; 6 | this.canvas = null; 7 | this.imageData = null; 8 | this.RGBA = null; 9 | } 10 | 11 | //行列だがrowsかcolsを1にすることでベクトルとしても扱う 12 | var CvMat = function(){ 13 | this.rows = 0; 14 | this.cols = 0; 15 | this.vals = null; 16 | } 17 | 18 | //スパース行列 19 | //本家のデータ構造とは大きく違う 20 | var CvSparseMat = function(){ 21 | this.rows = 0; 22 | this.cols = 0; 23 | this.vals = null; 24 | } 25 | 26 | var CvHistogram = function(){ 27 | this.type = 0; 28 | this.bins = null; 29 | this.thres = null; 30 | this.thres2 = null; 31 | this.mat = null; 32 | this.ranges = null; 33 | } 34 | 35 | var CvScalar = function(){ 36 | this.val = new Array(0, 0, 0, 255); 37 | } 38 | 39 | var CvPoint = function(){ 40 | this.x = 0; 41 | this.y = 0; 42 | } 43 | 44 | var CvSize = function(){ 45 | this.width = 0; 46 | this.height = 0; 47 | } 48 | 49 | 50 | //-----反復アルゴリズムの終了条件 51 | //その定数 52 | const CV_DEF_EPS = 0.00001; 53 | const CV_DEF_MAX_ITE = 100000; 54 | 55 | var CvTermCriteria = function(){ 56 | this.type = 0; //CV_TERMCRIT定数の組み合わせ 57 | this.max_iter = CV_DEF_MAX_ITE; //反復数の最大値 58 | this.eps = CV_DEF_EPS; //目標精度 59 | } 60 | 61 | 62 | //------------------定数------------------------ 63 | //チャンネル数 64 | const CHANNELS = 4; 65 | 66 | 67 | 68 | //-----------------構造体------------------------ 69 | 70 | //反復アルゴリズムのための終了条件 71 | //CvTermCriteria型の変数に利用する 72 | var CV_TERMCRIT = { 73 | ITER: 0, 74 | NUMBER: 0, 75 | EPS: 2 76 | } 77 | 78 | //ヒストグラムの種類 79 | var CV_HIST = { 80 | ARRAY: 0, 81 | SPARSE: 1 82 | } 83 | 84 | //DFTの種類 85 | var CV_DXT = { 86 | FORWARD: 0, //順変換 スケーリングなし 87 | INVERSE: 1, //逆変換 スケーリングなし 88 | FORWARD_SCALE: 2, //順変換 スケーリングあり 89 | INVERSE_SCALE: 3 //逆変換 スケーリングあり 90 | } 91 | 92 | //特異値分解のアルゴリズム 93 | var CV_SVD = { 94 | ZERO : 0, 95 | MODIFY_A : 1, 96 | U_T : 2, 97 | V_T : 3 98 | } 99 | 100 | //ノルムの種類 101 | var CV_NORM = { 102 | C : 0, 103 | L1 : 1, 104 | L2 : 2, 105 | L2Square : 3 106 | } 107 | 108 | //四則演算の種類 109 | var FOUR_ARITHMETIC = { 110 | ADD : 0, 111 | SUB : 1, 112 | MULT : 2, 113 | DIV : 3 114 | } 115 | 116 | //逆行列の演算の種類 117 | var CV_INV = { 118 | LU: 0, 119 | SVD: 1, 120 | SVD_SYM: 2 121 | } 122 | 123 | //エラー文 124 | var ERROR = { 125 | IS_UNDEFINED_OR_NULL : "がundefinedかnullです" 126 | ,DIFFERENT_SIZE : "IplImageサイズは全て同じにして下さい" 127 | ,DIFFERENT_ROWS_OR_COLS: "行と列が正しくありません" 128 | ,DIFFERENT_LENGTH: "の長さは全て同じにして下さい" 129 | ,INVALID_SIZE : "の長さが不正です" 130 | ,ONLY_ADD_NUMBER : "は奇数にして下さい" 131 | ,ONLY_INTERGER_NUMBER : "は整数にして下さい" 132 | ,ONLY_POSITIVE_NUMBER : "は正の値にして下さい" 133 | ,NOT_READ_FILE : "ファイルが読み込めません" 134 | ,NOT_GET_CONTEXT : "contextが読み込めません" 135 | ,PLEASE_SQUARE_MAT : "は正方行列にしてください" 136 | ,SWITCH_VALUE : "の値が正しくありません" 137 | ,APERTURE_SIZE : "aperture_sizeは1, 3, 5または7 のいずれかにしてください" 138 | ,ONLY_NUMBER : "は0から3にして下さい" 139 | } 140 | 141 | 142 | 143 | 144 | //--------------------------メソッド------------------------- 145 | 146 | //rows行cols列の行列を作る 147 | //C言語でいう a[rows][cols] 148 | //入力 149 | //rows 整数 (y座標) 150 | //cols 整数 (x座標) 151 | //出力 152 | //CvMat型 153 | function cvCreateMat(rows, cols){ 154 | var rtn = null; 155 | try{ 156 | if(cvUndefinedOrNull(rows) || cvUndefinedOrNull(cols)) 157 | throw "rows or cols" + ERROR.IS_UNDEFINED_OR_NULL; 158 | // if(!cvIsInt(rows) || !cvIsInt(cols) || rows < 1 || cols < 1) 159 | // throw "rows or cols" + ERROR.ONLY_NORMAL_NUMBER; 160 | 161 | rtn = new CvMat(); 162 | rtn.rows = rows; 163 | rtn.cols = cols; 164 | rtn.vals = new Array(rows * cols); 165 | } 166 | catch(ex){ 167 | alert("cvCreateMat : " + ex); 168 | } 169 | 170 | return rtn; 171 | } 172 | 173 | //rows行cols列の単位行列を作る 174 | //C言語でいう a[rows][cols] 175 | //入力 176 | //rows 整数 (y座標) 177 | //cols 整数 (x座標) 178 | //出力 179 | //CvMat型 180 | function cvCreateIdentityMat(rows, cols){ 181 | var rtn = null; 182 | try{ 183 | rtn = cvCreateMat(rows, cols); 184 | for(var i = 0 ; i < rows ; i++){ 185 | var ir = i * rows; 186 | for(var j = 0 ; j < cols ; j++){ 187 | rtn.vals[j + ir] = i == j ? 1 : 0; 188 | } 189 | } 190 | } 191 | catch(ex){ 192 | alert("cvCreateIdentityMat : " + ex); 193 | } 194 | 195 | return rtn; 196 | 197 | } 198 | 199 | //CvMatのコピー 200 | //入力 201 | //mat CvMat型 202 | //出力 203 | //CvMat型 204 | function cvmCopy(mat){ 205 | var rtn = cvCreateMat(mat.rows, mat.cols); 206 | for(var i = 0 ; i < rtn.rows * rtn.cols ; i++){ 207 | rtn.vals[i] = mat.vals[i]; 208 | } 209 | return rtn; 210 | } 211 | 212 | 213 | //行列に値を代入 214 | //入力 215 | //mat CvMat型 代入される行列 216 | //row 整数 代入する行番号(y座標) 217 | //col 整数 代入する列番号(x座標) 218 | //val 数値 代入される値 219 | //出力 220 | //なし 221 | function cvmSet(mat, row, col, value){ 222 | try{ 223 | if(cvUndefinedOrNull(mat) || cvUndefinedOrNull(value)|| 224 | cvUndefinedOrNull(row) || cvUndefinedOrNull(col)) 225 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 226 | 227 | mat.vals[col + row * mat.cols] = value; 228 | } 229 | catch(ex){ 230 | alert("cvmSet : " + ex); 231 | } 232 | } 233 | 234 | //行列から値を取得 235 | //入力 236 | //mat CvMat型 取得される行列 237 | //row 整数 取得する行番号(y座標) 238 | //col 整数 取得する列番号(x座標) 239 | //出力 240 | //数値 241 | function cvmGet(mat, row, col){ 242 | var rtn = null; 243 | try{ 244 | if(cvUndefinedOrNull(mat) || cvUndefinedOrNull(row) || cvUndefinedOrNull(col)) 245 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 246 | 247 | rtn = mat.vals[col + row * mat.cols]; 248 | } 249 | catch(ex){ 250 | alert("cvmGet : " + ex); 251 | } 252 | return rtn; 253 | } 254 | 255 | //行列の足し算 256 | //入力 257 | //matA CvMat型 足す行列 258 | //matB CvMat型 足される行列 259 | //出力 260 | //CvMat型 結果が代入される行列 261 | function cvmAdd(matA, matB){ 262 | var matX = null; 263 | try{ 264 | if(cvUndefinedOrNull(matA) || cvUndefinedOrNull(matB)) 265 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 266 | if(matA.rows != matB.rows || matA.cols != matB.cols) 267 | throw "引数の" + ERROR.DIFFERENT_SIZE; 268 | 269 | matX = cvCreateMat(matA.rows, matA.cols); 270 | 271 | for(var i = 0 ; i < matX.rows ; i++){ 272 | var im = i * matX.cols; 273 | for(var j = 0 ; j < matX.cols ; j++){ 274 | var ji = j + im; 275 | matX.vals[ji] = matA.vals[ji] + matB.vals[ji]; 276 | } 277 | } 278 | } 279 | catch(ex){ 280 | alert("cvmAdd : " + ex); 281 | } 282 | 283 | return matX; 284 | } 285 | 286 | //行列の引き算 287 | //入力 288 | //matA CvMat型 引く行列 289 | //matB CvMat型 引かれる行列 290 | //出力 291 | //CvMat型 結果が代入される行列 292 | function cvmSub(matA, matB){ 293 | 294 | var matX = null; 295 | try{ 296 | if(cvUndefinedOrNull(matA) || cvUndefinedOrNull(matB)) 297 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 298 | if(matA.rows != matB.rows || matA.cols != matB.cols) 299 | throw "引数の" + ERROR.DIFFERENT_SIZE; 300 | 301 | matX = cvCreateMat(matA.rows, matA.cols); 302 | 303 | for(var i = 0 ; i < matX.rows ; i++){ 304 | var im = i * matX.cols; 305 | for(var j = 0 ; j < matX.cols ; j++){ 306 | var ji = j + im; 307 | matX.vals[ji] = matA.vals[ji] - matB.vals[ji]; 308 | } 309 | } 310 | } 311 | catch(ex){ 312 | alert("cvmSub : " + ex); 313 | } 314 | 315 | return matX; 316 | } 317 | 318 | //行列の掛け算 319 | //入力 320 | //matA CvMat型 掛ける行列 321 | //matB CvMat型 掛けられる行列 322 | //出力 323 | //CvMat型 結果が代入される行列 324 | function cvmMul(matA, matB){ 325 | 326 | var matX = null; 327 | 328 | try{ 329 | if(cvUndefinedOrNull(matA) || cvUndefinedOrNull(matB)) 330 | throw "引数のどれかの" + ERROR.IS_UNDEFINED_OR_NULL; 331 | if(matA.cols != matB.rows) 332 | throw "引数のどれかの" + ERROR.DIFFERENT_ROWS_OR_COLS; 333 | 334 | matX = cvCreateMat(matA.rows, matB.cols); 335 | 336 | for(var i = 0 ; i < matX.rows ; i++){ 337 | var im = i * matX.cols; 338 | var imA = i * matA.cols; 339 | for(var j = 0 ; j < matX.cols ; j++){ 340 | var v = 0; 341 | for(var l = 0 ; l < matA.cols ; l++) 342 | v += matA.vals[l + imA] * matB.vals[j + l * matB.cols]; 343 | matX.vals[j + im] = v; 344 | } 345 | } 346 | } 347 | catch(ex){ 348 | alert("cvmMul : " + ex); 349 | } 350 | 351 | return matX; 352 | } 353 | 354 | //行列の列を最後に追加 355 | //入力 356 | //mat1 CvMat型 357 | //vec2 CvMat型 358 | //col int型 359 | //出力 360 | //CvMat型 361 | function cvmInsertCol(mat1, mat2, col){ 362 | var rtn = null; 363 | try{ 364 | if(cvUndefinedOrNull(mat1) || cvUndefinedOrNull(mat2)) 365 | throw "mat1 or mat2" + ERROR.IS_UNDEFINED_OR_NULL; 366 | 367 | if(mat1.rows != mat2.rows) 368 | throw "mat1とmat2" + ERROR.DIFFERENT_ROWS_OR_COLS; 369 | 370 | rtn = cvCreateMat(mat1.rows, mat1.cols + 1); 371 | 372 | for(var i = 0 ; i < rtn.rows ; i++){ 373 | for(var j = 0 ; j < rtn.cols ; j++){ 374 | if(j == rtn.cols - 1) 375 | rtn.vals[j + i * rtn.cols] = mat2.vals[col + i * mat2.cols]; 376 | else 377 | rtn.vals[j + i * rtn.cols] = mat1.vals[j + i * mat1.cols]; 378 | } 379 | } 380 | 381 | } 382 | catch(ex){ 383 | alert("cvmInsertCol : " + ex); 384 | } 385 | return rtn; 386 | } 387 | 388 | //行列の転置 389 | //入力 390 | //matA CvMat型 転置される行列 391 | //出力 392 | //CvMat型 結果が代入される行列 393 | function cvmTranspose(matA){ 394 | var matX = null; 395 | try{ 396 | if(cvUndefinedOrNull(matA)) 397 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 398 | 399 | matX = cvCreateMat(matA.cols, matA.rows); 400 | 401 | for(var i = 0 ; i < matX.rows ; i++){ 402 | var im = i * matX.cols; 403 | var jm = i; 404 | for(var j = 0 ; j < matX.cols ; j++){ 405 | matX.vals[j + im] = matA.vals[jm]; 406 | jm += matA.cols; 407 | } 408 | } 409 | } 410 | catch(ex){ 411 | alert("cvmTranspose : " + ex); 412 | } 413 | return matX; 414 | } 415 | 416 | //mat1 - mat2の行列のノルムを計算する 417 | //入力 418 | //mat1 CvMat型 1番目の行列 419 | //mat2 CvMat型 2番目の行列 nullならmat1だけでノルム計算 420 | //normType CV_NORM型 ノルムのタイプ デフォルト CV_NORM.L1 421 | //mask CvMat型 マスクの行列(現在は利用不可) 422 | //出力 423 | //ノルムの計算結果 424 | function cvmNorm(mat1, mat2, normType, mask){ 425 | var rtn = 0; 426 | try{ 427 | if(cvUndefinedOrNull(mat1)) 428 | throw "mat1" + ERROR.IS_UNDEFINED_OR_NULL; 429 | if(!cvUndefinedOrNull(mat2) && (mat1.rows != mat2.rows || mat1.cols != mat2.cols)) 430 | throw "mat1 と mat2" + ERROR.DIFFERENT_ROWS_OR_COLS; 431 | 432 | if(cvUndefinedOrNull(normType)) 433 | normType = CV_NORM.L1; 434 | 435 | switch(normType){ 436 | case CV_NORM.C: 437 | if(cvUndefinedOrNull(mat2)){ 438 | rtn = Math.abs(mat1.vals[0]); 439 | for(var i = 0 ; i < mat1.rows ; i++){ 440 | var ir = i * mat1.rows; 441 | for(var j = 0 ; j < mat1.cols ; j++){ 442 | if(rtn < Math.abs(mat1.vals[j + ir])){ 443 | rtn = Math.abs(mat1.vals[j + ir]); 444 | } 445 | } 446 | } 447 | } 448 | else{ 449 | rtn = Math.abs(mat1.vals[0] - mat2.vals[0]); 450 | for(var i = 0 ; i < mat1.rows ; i++){ 451 | var ir = i * mat1.rows; 452 | for(var j = 0 ; j < mat1.cols ; j++){ 453 | if(rtn < Math.abs(mat1.vals[j + ir] - mat2.vals[j + ir])){ 454 | rtn = Math.abs(mat1.vals[j + ir] - mat2.vals[j + ir]); 455 | } 456 | } 457 | } 458 | 459 | } 460 | break; 461 | case CV_NORM.L1: 462 | if(cvUndefinedOrNull(mat2)){ 463 | var length = mat1.rows * mat1.cols; 464 | for(var i = 0 ; i < length ; i++){ 465 | rtn += Math.abs(mat1.vals[i]); 466 | } 467 | } 468 | else{ 469 | var length = mat1.rows * mat1.cols; 470 | for(var i = 0 ; i < length ; i++){ 471 | rtn += Math.abs(mat1.vals[i] - mat2.vals[i]); 472 | } 473 | } 474 | break; 475 | case CV_NORM.L2: 476 | case CV_NORM.L2Square: 477 | if(cvUndefinedOrNull(mat2)){ 478 | var length = mat1.rows * mat1.cols; 479 | for(var i = 0; i < length ; i++){ 480 | rtn += mat1.vals[i] * mat1.vals[i]; 481 | } 482 | if(normType == CV_NORM.L2){ 483 | rtn = Math.sqrt(rtn); 484 | } 485 | } 486 | else{ 487 | var length = mat1.rows * mat1.cols; 488 | for(var i = 0; i < length ; i++){ 489 | var v = mat1.vals[i] - mat2.vals[i]; 490 | rtn += v * v; 491 | } 492 | if(normType == CV_NORM.L2){ 493 | rtn = Math.sqrt(rtn); 494 | } 495 | } 496 | break; 497 | default: 498 | throw "normTypeがサポートされていない値を設定しています"; 499 | break; 500 | } 501 | } 502 | catch(ex){ 503 | alert("cvmNorm : " + ex); 504 | } 505 | 506 | return rtn; 507 | } 508 | 509 | //ベクトルの内積を求める 510 | //ひとつめのCvMatのrows行を横ベクトル、ふたつめのCvMatのcols列を縦ベクトルと見立てて内積を求める 511 | //入力 512 | //mat1 CvMat型 横ベクトルに見立てるひとつめの行列 513 | //rows int型 mat1の行番号 514 | //mat2 CvMat型 縦ベクトルに見立てるふたつめの行列 515 | //cols int型 mat2の列番号 516 | //出力 517 | //内積の計算結果 518 | function cvmDot(mat1, rows, mat2, cols){ 519 | 520 | var rtn = -1; 521 | 522 | try{ 523 | if(cvUndefinedOrNull(mat1) || cvUndefinedOrNull(mat2)) 524 | throw "mat1またはmat2" + ERROR.IS_UNDEFINED_OR_NULL; 525 | if(rows < 0 || cols < 0 || mat1.rows - 1 < rows || mat2.cols - 1 < cols) 526 | throw "mat1かmat2の指定された行か列が範囲外です"; 527 | 528 | if(mat1.cols != mat2.rows) 529 | throw "mat1とmat2の長さが違います"; 530 | 531 | rtn = 0; 532 | for(var i = 0 ; i < mat1.cols ; i++) 533 | rtn += mat1.vals[i + rows * mat1.cols] * mat2.vals[cols + i * mat2.cols]; 534 | } 535 | catch(ex){ 536 | alert("cvmDot : " + ex); 537 | } 538 | 539 | return rtn; 540 | } 541 | 542 | //行列のrankを求める 543 | //入力 544 | //org CvMat型 545 | //cvTermCriteria CvTermCriteria型 546 | //出力 547 | //rank数 548 | function cvmRank(org, cvTermCriteria){ 549 | 550 | var rtn = -1; 551 | try{ 552 | if(cvUndefinedOrNull(cvTermCriteria)) 553 | cvTermCriteria = new CvTermCriteria(); 554 | 555 | var mat = cvmCopy(org); 556 | for(var k = 0; k < mat.rows; k++){ 557 | var p = mat.vals[k + k * mat.cols];//ピボット係数 558 | if(p == 0){ 559 | //入れ替える 560 | for(var kk = k + 1 ; kk < mat.rows ; kk++){ 561 | if(Math.abs(mat.vals[k + kk * mat.cols]) > cvTermCriteria.eps){ 562 | p = mat.vals[k + kk * mat.cols]; 563 | for(var i = 0 ; i < mat.cols ; i++){ 564 | var tmp = mat.vals[i + k * mat.cols]; 565 | mat.vals[i + k * mat.cols] = mat.vals[i + kk * mat.cols]; 566 | mat.vals[i + kk * mat.cols] = tmp; 567 | } 568 | break; 569 | } 570 | } 571 | //入れ替える要素がない場合は次へ 572 | if(p == 0){ 573 | break; 574 | } 575 | } 576 | 577 | for (var i = k; i < mat.cols; i++) 578 | mat.vals[i + k * mat.cols] /= p; // ピボット係数を1にするためピボット行を割り算 579 | 580 | for (var i = 0; i < mat.rows; i++){// ピボット列の掃き出し 581 | if(i != k){ 582 | var d = mat.vals[k + i * mat.cols]; 583 | for(var j = k; j < mat.cols; j++){ 584 | mat.vals[j + i * mat.cols] -= d * mat.vals[j + k * mat.cols]; 585 | if(Math.abs(mat.vals[j + i * mat.cols]) < cvTermCriteria.eps) 586 | mat.vals[j + i * mat.cols] = 0; 587 | } 588 | } 589 | } 590 | } 591 | 592 | rtn = -1; 593 | for(var i = 0 ; i < mat.rows; i++){ 594 | for(var j = 0 ; j < mat.cols; j++){ 595 | if(Math.abs(mat.vals[j + i * mat.cols]) > cvTermCriteria.eps){ 596 | break; 597 | } 598 | if(j == mat.cols - 1){ 599 | rtn = i; 600 | break; 601 | } 602 | } 603 | if(rtn != -1){ 604 | break; 605 | } 606 | else if(i == mat.rows - 1){ 607 | rtn = mat.rows; 608 | break; 609 | } 610 | } 611 | 612 | } 613 | catch(ex){ 614 | alert("cvmRank : " + ex); 615 | } 616 | 617 | return rtn; 618 | } 619 | 620 | //行列式の演算 621 | //入力 622 | //mat CvMat型 行列式を求める行列 623 | //出力 624 | //演算結果 625 | function cvmDet(mat){ 626 | var rtn = null; 627 | try{ 628 | if(cvUndefinedOrNull(mat)) 629 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 630 | if(mat.rows != mat.cols || mat.rows == 0 || mat.cols == 0) 631 | throw "mat" + ERROR.PLEASE_SQUARE_MAT; 632 | 633 | if(mat.cols == 1) rtn = cvmGet(mat, 0, 0); 634 | if(mat.cols == 2){ 635 | rtn = mat.vals[0] * mat.vals[1 + 1 * mat.cols]; 636 | rtn -= mat.vals[1] * mat.vals[1 * mat.cols]; 637 | } 638 | else if(mat.cols == 3){ 639 | rtn = mat.vals[0] * mat.vals[1 + 1 * mat.cols] * mat.vals[2 + 2 * mat.cols]; 640 | rtn += mat.vals[1 * mat.cols] * mat.vals[1 + 2 * mat.cols] * mat.vals[2]; 641 | rtn += mat.vals[2 * mat.cols] * mat.vals[1] * mat.vals[2 + 1 * mat.cols]; 642 | rtn -= mat.vals[2 * mat.cols] * mat.vals[1 + 1 * mat.cols] * mat.vals[2]; 643 | rtn -= mat.vals[1 * mat.cols] * mat.vals[1] * mat.vals[2 + 2 * mat.cols]; 644 | rtn -= mat.vals[0] * mat.vals[1 + 2 * mat.cols] * mat.vals[2 + 1 * mat.cols]; 645 | } 646 | else{ 647 | rtn = 1; 648 | var buf; 649 | //三角行列作成 650 | for(var i = 0 ; i < mat.rows ; i++){ 651 | for(var j = 0; j < mat.cols ; j++){ 652 | if(i < j){ 653 | buf = mat.vals[ i + j * mat.cols ] / mat.vals[ i + i * mat.cols ]; 654 | for(var k = 0 ; k < mat.cols ; k++) 655 | mat.vals[k + j * mat.cols] -= mat.vals[k + i * mat.cols] * buf; 656 | } 657 | } 658 | } 659 | //対角部分の積 660 | for(var i = 0 ; i < mat.rows ; i++){ 661 | rtn *= mat.vals[i + i * mat.cols]; 662 | } 663 | } 664 | } 665 | catch(ex){ 666 | alert("cvmDet : " + ex); 667 | } 668 | 669 | return rtn; 670 | } 671 | 672 | //QR分解 673 | //入力 674 | //mat CvMat型 QR分解する行列 rows >= cols 675 | //cvTermCriteria CvTermCriteria型 676 | //出力 677 | //[Q, R] 配列内のデータはそれぞれCvMat型 678 | function cvmQR(mat, cvTermCriteria){ 679 | var rtn = null; 680 | try{ 681 | //バリデーション 682 | if(cvUndefinedOrNull(mat)) 683 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 684 | 685 | if(mat.rows < mat.cols){ 686 | throw "mat.rows >= mat.colsでなければいけません"; 687 | } 688 | 689 | //デフォルト 690 | if(cvUndefinedOrNull(cvTermCriteria)) 691 | cvTermCriteria = new CvTermCriteria(); 692 | 693 | var Q = cvCreateIdentityMat(mat.rows, mat.rows); 694 | var R = cvCreateMat(mat.rows, mat.cols); 695 | for(var i = 0 ; i < mat.rows * mat.cols ; i++) 696 | R.vals[i] = mat.vals[i]; 697 | 698 | //ループによりQR分解 699 | for(var r = 0 ; r < mat.cols ; r++){ 700 | //r列目のr行目からmat.rowsまでのノルム 701 | var norm = 0; 702 | for(var i = r ; i < mat.rows ; i++) 703 | norm += R.vals[r + i * mat.cols] * R.vals[r + i * mat.cols]; 704 | norm = Math.sqrt(norm); 705 | 706 | //ハウスホルダー変換を行う列ベクトルを取り出す 707 | var vec1 = cvCreateMat(mat.rows - r, 1); 708 | for(var i = 0 ; i < vec1.rows ; i++) 709 | vec1.vals[i] = R.vals[r + (r + i) * R.cols]; 710 | //ハウスホルダー変換に使うvec2を準備 711 | var vec2 = cvCreateMat(vec1.rows, 1); 712 | vec2.vals[0] = norm; 713 | for(var i = 1 ; i < vec2.rows ; vec2.vals[i++] = 0); 714 | 715 | //ハウスホルダー変換 716 | var hh = cvmHouseHolder(vec1, vec2); 717 | 718 | //QR分解する位置にhhを代入 719 | var H = cvCreateIdentityMat(R.rows, R.rows); 720 | var p = H.rows - hh.rows; 721 | for(var i = 0 ; i < hh.rows ; i++){ 722 | for(var j = 0 ; j < hh.cols ; j++){ 723 | H.vals[p + j + (p + i) * H.cols] = hh.vals[j + i * hh.cols]; 724 | } 725 | } 726 | 727 | R = cvmMul(H, R); 728 | Q = cvmMul(H, Q); 729 | } 730 | 731 | rtn = [Q, R]; 732 | 733 | } 734 | catch(ex){ 735 | alert("cvmQR : " + ex); 736 | } 737 | 738 | return rtn; 739 | } 740 | 741 | //LU分解の演算 742 | //入力 743 | //mat CvMat型 LU分解される行列 744 | //出力 745 | // [L, U] 746 | //L CvMat型 Lの結果が代入される行列 747 | //U CvMat型 Uの結果が代入される行列 748 | //なし 749 | function cvmLU(mat){ 750 | var rtn = null; 751 | try{ 752 | if(cvUndefinedOrNull(mat)) 753 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 754 | if(mat.rows != mat.cols || mat.rows == 0 || mat.cols == 0) 755 | throw "mat" + ERROR.PLEASE_SQUARE_MAT; 756 | 757 | var L = cvCreateMat(mat.rows, mat.cols); 758 | var U = cvCreateMat(mat.rows, mat.cols); 759 | 760 | //初期化 761 | for(var i=0; i < mat.rows; i++){ 762 | for(var j=0; j < mat.cols; j++){ 763 | L.vals[j + i * L.cols] = 0; 764 | U.vals[j + i * U.cols] = 0; 765 | if(i==j) L.vals[j + i * L.cols]=1.0; 766 | } 767 | } 768 | 769 | var sum; 770 | for(var i=0; i < mat.rows; i++){ 771 | for(var j=0; j < mat.cols; j++){ 772 | if( i > j ){ 773 | //-- L成分を求める -- 774 | sum=0.0; 775 | for(var k=0; k < j; k++){ 776 | sum+=L.vals[k + i * L.cols] * U.vals[j + k * U.cols]; 777 | } 778 | L.vals[j + i * L.cols] = (mat.vals[j + i * mat.cols] - sum) / U.vals[j + j * U.cols]; 779 | }else{ 780 | // --U成分を求める-- 781 | sum=0.0; 782 | for(var k=0;k cvTermCriteria.eps){ 842 | throw "vec1とvec2のノルムが違います"; 843 | } 844 | 845 | 846 | //単位行列 847 | var im = cvCreateIdentityMat(length, length); 848 | 849 | //差分の正規化 850 | var dstV = cvmSub(vec1, vec2); 851 | var dstNrm = cvmNorm(dstV, null, CV_NORM.L2); 852 | 853 | //差がないようならそのまま単位行列がhouseholder行列となる 854 | if(dstNrm < cvTermCriteria.eps) return im; 855 | 856 | for(var i = 0 ; i < dstV.rows * dstV.cols; dstV.vals[i++] /= dstNrm); 857 | 858 | var dstMat = cvmMul(dstV, cvmTranspose(dstV)); 859 | 860 | for(var i = 0 ; i < dstMat.rows * dstMat.cols; dstMat.vals[i++] *= 2); 861 | 862 | //単位行列からひく 863 | rtn = cvmSub(im, dstMat); 864 | } 865 | catch(ex){ 866 | alert("cvmHouseHolder : " + ex); 867 | } 868 | 869 | return rtn; 870 | } 871 | 872 | //実対称行列の固有値及び固有ベクトルを求める 873 | // ※実対称行列に限定しているのは固有値が実数であるから 874 | // ※固有値は大きい順にソートされて出力されるが小さい固有値ほど誤差が大きい、計算精度には常に注意せよ 875 | //入力 876 | //mat CvMat型 固有値と固有ベクトルを求める対称行列 877 | //cvTermCriteria CvTermCriteria型 対角化の精度 878 | //出力 879 | //[eValues, eVects] 880 | //eValues CvMat型 固有値が大きい順に並ぶ1列(行)の行列(つまりベクトル) 881 | //eVects CvMat型 固有ベクトルを縦ベクトルにして並べる 882 | function cvmEigen(mat, cvTermCriteria){ 883 | var rtn = null; 884 | try{ 885 | //バリデーション 886 | if(cvUndefinedOrNull(mat)) 887 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 888 | if(mat.rows != mat.cols || mat.rows == 0 || mat.cols == 0) 889 | throw "mat" + ERROR.PLEASE_SQUARE_MAT; 890 | 891 | //対称化のチェック 892 | for(var i = 0 ; i < mat.rows ; i++){ 893 | for(var j = i + 1 ; j < mat.cols ; j++){ 894 | if(mat.vals[j + i * mat.cols] != mat.vals[i + j *mat.cols]){ 895 | throw "matは対称行列ではありません"; 896 | } 897 | } 898 | } 899 | 900 | //精度の値を確認 901 | if(cvUndefinedOrNull(cvTermCriteria)) 902 | cvTermCriteria = new CvTermCriteria(); 903 | 904 | //オリジナルの配列をコピー、QR分解により三重対角行列が代入される 905 | var rq = cvmCopy(mat); 906 | 907 | //固有ベクトルの組(行列として結果は求まる) 908 | var eVects = cvCreateIdentityMat(mat.rows, mat.rows); 909 | 910 | //---QR法による三重対角化--- 911 | var isOK = false; 912 | var length = rq.rows * rq.cols; 913 | for(var loop = 0 ; loop < cvTermCriteria.max_iter ; loop++){ 914 | 915 | var qr = cvmQR(rq); 916 | if(qr == null) return rtn; 917 | 918 | var Qt = cvmTranspose(qr[0]); 919 | 920 | eVects = cvmMul(eVects, Qt); 921 | 922 | var tmp = cvmMul(qr[1], Qt); 923 | 924 | isOK = true; 925 | 926 | //前回のループとの差があるかチェック 927 | //ただしこのアルゴリズムではループを抜ける条件が厳しすぎて時間がかかるので要検討 928 | var ssum = 0; 929 | for(var i = 0 ; i < length ; i++){ 930 | ssum += Math.abs(tmp.vals[i] - rq.vals[i]); 931 | } 932 | //差がなければループを抜ける 933 | if(ssum < cvTermCriteria.eps * length){ 934 | isOK = true; 935 | break; 936 | } 937 | rq = tmp; 938 | 939 | /* 940 | //精度のチェック(rqが対角行列か三重対角行列に収束するのでそれをチェック) 941 | for(var i = 0 ; i < tmp.rows; i++){ 942 | for(var j = 0 ; j < tmp.cols; j++){ 943 | 944 | //前回との差 945 | var s = Math.abs(tmp.vals[j + i * tmp.cols] - rq.vals[j + i * rq.cols]); 946 | 947 | //三重対角化の成分についてチェック 948 | if(i - 1 == j || i + 1 == j){ 949 | //前回のループとの差があるなら次のループへ 950 | if(s > cvTermCriteria.eps){ 951 | isOK = false; 952 | break; 953 | } 954 | } 955 | //対角成分ではなく、かつ前回のと差があり、現在の値が閾値より大きい 956 | else if(s > cvTermCriteria.eps && Math.abs(tmp.vals[j + i * tmp.cols]) > cvTermCriteria.eps){ 957 | isOK = false; 958 | break; 959 | } 960 | } 961 | //精度のチェックでひっかかっているならループをぬける 962 | if(!isOK) break; 963 | } 964 | 965 | //精度が問題なければfor文を抜ける 966 | if(isOK) break; 967 | */ 968 | } 969 | 970 | //精度が問題ないか 971 | if(!isOK){ 972 | cvDWriteMatrix(rq, "rq"); 973 | throw "最大ループ回数(" + cvTermCriteria.max_iter + ")を超えましたが精度" + cvTermCriteria.eps + "が足りていません"; 974 | } 975 | 976 | //固有値を代入 977 | var eValues = cvCreateMat(rq.rows, 1); 978 | for(var i = 0 ; i < eValues.rows; i++){ 979 | eValues.vals[i] = rq.vals[i + i * rq.cols]; 980 | } 981 | 982 | //降順に並び替え 983 | for(var i = 0 ; i < eValues.rows ; i++){ 984 | //最大値のindexを探索 985 | var maxV = eValues.vals[i]; 986 | var maxIndex = i; 987 | for(var j = i + 1 ; j < eValues.rows; j++){ 988 | if(maxV < eValues.vals[j]){ 989 | maxV = eValues.vals[j]; 990 | maxIndex = j; 991 | } 992 | } 993 | 994 | //固有値を入れ替える 995 | var tmp = eValues.vals[i]; 996 | eValues.vals[i] = eValues.vals[maxIndex]; 997 | eValues.vals[maxIndex] = tmp; 998 | 999 | //固有ベクトルを入れ替える 1000 | for(var y = 0 ; y < eVects.rows ; y++){ 1001 | tmp = eVects.vals[i + y * eVects.cols]; 1002 | eVects.vals[i + y * eVects.cols] = eVects.vals[maxIndex + y * eVects.cols]; 1003 | eVects.vals[maxIndex + y * eVects.cols] = tmp; 1004 | } 1005 | } 1006 | 1007 | rtn = [eValues, eVects]; 1008 | } 1009 | catch(ex){ 1010 | alert("cvmEigen : " + ex); 1011 | } 1012 | 1013 | return rtn; 1014 | } 1015 | 1016 | //特異値分解の演算 LWR 1017 | //入力 1018 | //A CvMat型 特異値分解される行列(M*N) 1019 | //cvTermCriteria CvTermCriteria型 計算精度 1020 | //flags CV_SVD型 svdの種類 CV_SVD.ZEROのみサポート デフォルト = CV_SVD.ZERO 1021 | //出力 1022 | //[W, L, R] 1023 | //W CvMat型 特異値行列の非負の行列(M*NまたはN*N) 1024 | //L CvMat型 左直交行列(M*MまたはM*N) 1025 | //R CvMat型 右直交行列(N*N) 1026 | function cvmSVD(A, cvTermCriteria, flags){ 1027 | 1028 | var rtn = null; 1029 | try{ 1030 | //バリデーション 1031 | if(cvUndefinedOrNull(A)) 1032 | throw "第一引数" + ERROR.IS_UNDEFINED_OR_NULL; 1033 | 1034 | //デフォルト 1035 | if(cvUndefinedOrNull(cvTermCriteria)) 1036 | cvTermCriteria = new CvTermCriteria(); 1037 | 1038 | if(cvUndefinedOrNull(flags)) flags = CV_SVD.ZERO; 1039 | 1040 | switch(flags){ 1041 | case CV_SVD.ZERO: 1042 | { 1043 | var trA = cvmTranspose(A); 1044 | /* 1045 | //こちらでも特異値が求まるはずだが精度が良くない 1046 | 1047 | //左特異ベクトル 1048 | var AtrA = cvmMul(A, trA); 1049 | AtrA = cvmMul(AtrA, AtrA); 1050 | var left = cvmEigen(AtrA, cvTermCriteria); 1051 | L = left[1]; 1052 | 1053 | //右特異ベクトル 1054 | var trAA = cvmMul(trA, A); 1055 | trAA = cvmMul(trAA, trAA); 1056 | var right = cvmEigen(trAA, cvTermCriteria); 1057 | R = right[1]; 1058 | 1059 | //閾値以下の固有値の個数 1060 | var r = 0; 1061 | for(var i = 0 ; i < left[0].rows ; i++){ 1062 | if(left[0].vals[i] < cvTermCriteria.eps) 1063 | break; 1064 | r++; 1065 | } 1066 | 1067 | // cvDWriteMatrix(left[0], "left0"); 1068 | // cvDWriteMatrix(right[0], "right0"); 1069 | //特異値 1070 | var W = cvCreateMat(A.rows, A.cols); 1071 | for(var i = 0 ; i < W.rows * W.cols ; W.vals[i++]=0); 1072 | for(var i = 0 ; i < r; i++) 1073 | W.vals[i + i * W.cols] = Math.sqrt(Math.sqrt(left[0].vals[i])); 1074 | */ 1075 | var trAA = cvmMul(trA,A); 1076 | 1077 | var ee = cvmEigen(trAA, cvTermCriteria); 1078 | 1079 | //ee[1]を正規化したものがR(右特異ベクトル) 1080 | var R = cvmCopy(ee[1]); 1081 | for(var j = 0 ; j < R.cols ; j++){ 1082 | var norm = 0; 1083 | for(var i = 0 ; i < R.rows ; i++){ 1084 | norm += R.vals[j + i * R.cols] * R.vals[j + i * R.cols]; 1085 | } 1086 | norm = Math.sqrt(norm); 1087 | 1088 | for(var i = 0 ; i < R.rows ; i++){ 1089 | R.vals[j + i * R.cols] /= norm; 1090 | } 1091 | } 1092 | 1093 | //閾値以下の固有値の個数 1094 | var r = 0; 1095 | for(var i = 0 ; i < ee[0].rows ; i++){ 1096 | if(ee[0].vals[i] < cvTermCriteria.eps) 1097 | break; 1098 | r++; 1099 | } 1100 | r = Math.min(A.cols, Math.min(A.rows, r)); 1101 | 1102 | //固有値の個数分だけRからベクトルを抜き出す 1103 | var R1 = cvCreateMat(trAA.rows, r); 1104 | for(var j = 0 ; j < R1.cols ; j++){ 1105 | for(var i = 0 ; i < R1.rows ; i++){ 1106 | R1.vals[j + i * R1.cols] = ee[1].vals[j + i * ee[1].cols]; 1107 | } 1108 | } 1109 | 1110 | //固有値ベクトルの二乗根 1111 | var d = cvCreateMat(r, r); 1112 | for(var i = 0 ; i < r * r ; d.vals[i++]=0); 1113 | for(var i = 0 ; i < r ; i++) 1114 | d.vals[i + i * d.cols] = Math.sqrt(ee[0].vals[i]); 1115 | 1116 | //特異値 1117 | var W = cvCreateMat(A.rows, A.cols); 1118 | for(var i = 0 ; i < W.rows * W.cols ; W.vals[i++]=0); 1119 | for(var i = 0 ; i < d.rows; i++) 1120 | W.vals[i + i * W.cols] = d.vals[i + i * d.cols]; 1121 | 1122 | 1123 | //固有値ベクトルの二乗根の逆数 1124 | var invD = cvCreateMat(r, r); 1125 | for(var i = 0 ; i < r * r ; invD.vals[i++]=0); 1126 | for(var i = 0 ; i < r ; i++) 1127 | invD.vals[i + i * invD.cols] = 1.0/d.vals[i + i * d.cols]; 1128 | 1129 | var L1 = cvmMul(cvmMul(A, R1), invD); 1130 | 1131 | var L = null; 1132 | if(L1.rows > L1.cols){ 1133 | 1134 | //ユニタリー行列となるようにする 1135 | //グラムシュミットにより新たな直交ベクトルを加えていく 1136 | var last = A.rows - L1.cols; 1137 | L = L1; 1138 | for(var t = 0 ; t < last ; t++){ 1139 | var tmp = cvCreateMat(L.rows, L.cols + 1); 1140 | for(var i = 0 ; i < L.rows ; i++){ 1141 | for(var j = 0 ; j < L.cols ; j++){ 1142 | tmp.vals[j + i * tmp.cols] = L.vals[j + i * L.cols]; 1143 | } 1144 | } 1145 | 1146 | var ov = cvmAddNewOrthogonalVec(L); 1147 | for(var i = 0 ; i < L.rows ; i++){ 1148 | tmp.vals[(tmp.cols - 1) + i * tmp.cols] = ov.vals[i]; 1149 | } 1150 | L = tmp; 1151 | } 1152 | } 1153 | else{ 1154 | L = L1; 1155 | } 1156 | rtn = [W, L, R]; 1157 | } 1158 | break; 1159 | 1160 | default: 1161 | throw "flagsはCV_SVD.ZEROしか現在サポートされていません"; 1162 | break; 1163 | } 1164 | } 1165 | catch(ex){ 1166 | alert("cvmSVD : " + ex); 1167 | } 1168 | 1169 | return rtn; 1170 | } 1171 | 1172 | //行列内のどの縦ベクトルとも直交する正規ベクトルを求める 1173 | function cvmAddNewOrthogonalVec(mat){ 1174 | var rtn = null; 1175 | try{ 1176 | //追加する横ベクトルの初期化を乱数で生成 1177 | var tmpV = cvCreateMat(1, mat.rows); 1178 | for(var i = 0 ; i < tmpV.cols ; tmpV.vals[i++] = Math.random()); 1179 | 1180 | //新たな直交の縦ベクトルが代入される 1181 | rtn = cvmTranspose(cvmCopy(tmpV)); 1182 | for(var j = 0 ; j < mat.cols ; j++){ 1183 | //matからj番目の縦ベクトルを抽出 1184 | var matV = cvCreateMat(mat.rows, 1); 1185 | for(var i = 0 ; i < mat.rows ; i++){ 1186 | matV.vals[i] = mat.vals[j + i * mat.cols]; 1187 | } 1188 | //シュミットの直交化法のアルゴリズムに従って計算 1189 | var tmp = cvmMul(tmpV, matV); 1190 | for(var i = 0 ; i < matV.rows ; matV.vals[i++] *= tmp.vals[0]); 1191 | rtn = cvmSub(rtn, matV); 1192 | } 1193 | 1194 | //正規化 1195 | var norm = cvmNorm(rtn, null, CV_NORM.L2); 1196 | for(var i = 0 ; i < rtn.rows ; rtn.vals[i++] /= norm); 1197 | } 1198 | catch(ex){ 1199 | alert("cvmAddNewOrthogonalVec : " + ex); 1200 | } 1201 | return rtn; 1202 | } 1203 | 1204 | //(擬似)逆行列の演算 1205 | //入力 1206 | //mat CvMat型 逆行列を求める行列 1207 | //cvTermCriteria CvCriteria型 計算精度 1208 | //method CV_INV配列 アルゴリズムの種類 1209 | //出力 1210 | //CvMat型 求まった行列が代入される 1211 | function cvmInverse(mat, cvTermCriteria, method){ 1212 | var invMat = null; 1213 | try{ 1214 | //バリデーション 1215 | if(cvUndefinedOrNull(mat)) 1216 | throw "mat" + ERROR.IS_UNDEFINED_OR_NULL; 1217 | 1218 | //初期化 1219 | if(cvUndefinedOrNull(method)){ 1220 | if(mat.rows == mat.cols) method = CV_INV.LU; 1221 | else method = CV_INV.SVD; 1222 | } 1223 | 1224 | if(method == CV_INV.LU){ 1225 | //逆行列の存在確認 1226 | var det = cvmDet(mat); 1227 | if(Math.abs(det) < cvTermCriteria.eps){ 1228 | throw "cvmInverse : 逆行列は存在しません"; 1229 | } 1230 | } 1231 | 1232 | if(method == CV_INV.SVD_SYM) 1233 | throw "CV_INV.SVD_SYM は現在サポートされていません"; 1234 | 1235 | invMat = cvCreateMat(mat.rows, mat.cols); 1236 | 1237 | switch(method){ 1238 | case CV_INV.LU: 1239 | if(mat.cols != mat.rows) 1240 | throw "CV_INV.LUの場合、mat" + ERROR.PLEASE_SQUARE_MAT; 1241 | 1242 | //前進代入 1243 | function Lforwardsubs(L, b, y){ 1244 | for(var i = 0 ; i < L.rows ; i++) 1245 | y.vals[i * y.cols] = b.vals[i * b.cols]; 1246 | 1247 | for(var i = 0 ; i < L.rows ; i++){ 1248 | y.vals[i * y.cols] /= L.vals[i + i * L.cols]; 1249 | for(var j = i + 1 ; j < L.cols ; j++){ 1250 | y.vals[j * y.cols] -= y.vals[i * y.cols] * L.vals[ i + j * L.cols]; 1251 | } 1252 | } 1253 | } 1254 | //後退代入 1255 | function Ubackwardsubs(U, y, x){ 1256 | for(var i = 0 ; i < U.rows; i++) 1257 | x.vals[i * x.cols] = y.vals[i * y.cols]; 1258 | 1259 | for(var i = U.rows-1 ; i >= 0; i--){ 1260 | x.vals[i * x.cols] /= U.vals[i + i * U.cols]; 1261 | for(var j = i-1 ; j >= 0 ; j--){ 1262 | x.vals[j * x.cols] -= x.vals[i * x.cols] * U.vals[i + j * U.cols]; 1263 | } 1264 | } 1265 | } 1266 | 1267 | // -- matのLU分解 -- 1268 | var LU = cvmLU(mat, L, U); 1269 | var L = LU[0]; 1270 | var U = LU[1]; 1271 | 1272 | for(var i = 0 ; i < mat.cols ; i++) 1273 | { 1274 | var initVec = cvCreateMat(mat.rows, 1); 1275 | for(var v = 0 ; v < mat.rows ; v++) 1276 | initVec.vals[v] = (v == i) ? 1 : 0 ; 1277 | 1278 | var dmyVec = cvCreateMat(mat.rows, 1); 1279 | var inverseVec = cvCreateMat(mat.rows, 1); 1280 | 1281 | Lforwardsubs(L, initVec, dmyVec); 1282 | Ubackwardsubs(U, dmyVec, inverseVec); 1283 | 1284 | for(var v = 0 ; v < mat.rows ; v++){ 1285 | invMat.vals[i + v * invMat.cols] = inverseVec.vals[v * inverseVec.cols]; 1286 | } 1287 | } 1288 | 1289 | break; 1290 | case CV_INV.SVD: 1291 | //デフォルト 1292 | if(cvUndefinedOrNull(cvTermCriteria)) 1293 | cvTermCriteria = new CvTermCriteria(); 1294 | 1295 | var svd = cvmSVD(mat, cvTermCriteria); 1296 | var W = svd[0]; 1297 | var L = svd[1]; 1298 | var R = svd[2]; 1299 | 1300 | var short =Math.min(W.rows, W.cols); 1301 | 1302 | var WW = cvCreateMat(W.cols, W.rows); 1303 | //初期化 1304 | for(var i = 0 ; i < WW.rows * WW.cols ; WW.vals[i++] = 0); 1305 | 1306 | for(var i = 0 ; i < short ; i++){ 1307 | WW.vals[i + i * WW.cols] = (W.vals[i + i * W.cols] != 0) ? 1.0/W.vals[i + i * W.cols] : 0; 1308 | } 1309 | 1310 | var trL = cvmTranspose(L); 1311 | 1312 | invMat = cvmMul(cvmMul(R, WW), trL); 1313 | 1314 | break; 1315 | case CV_INV.SVD_SYM: break; 1316 | } 1317 | } 1318 | catch(ex){ 1319 | alert("cvmInverse : " + ex); 1320 | } 1321 | 1322 | return invMat; 1323 | } 1324 | 1325 | //Orthogonal Matching Pursuit 1326 | //スパースコーディングの係数選択法 1327 | //入力 1328 | //vec CvMat型 スパース表現にする行列を1列に並べ替えた縦ベクトル 1329 | //dic CvMat型 辞書行列 dic.rows == vec.rows 1330 | //cvTermCriteria CvTermCriteria型 計算精度 1331 | //eigenCriteria CvTermCriteria型 内部の固有値計算の精度 1332 | //出力 1333 | //CvMat型 辞書係数 rows = vec.rowsの縦ベクトル 1334 | function cvmOMP(vec, dic, cvTermCriteria, eigenTermCriteria){ 1335 | var rtn = null; 1336 | try{ 1337 | //バリデーション 1338 | if(cvUndefinedOrNull(vec) || cvUndefinedOrNull(dic)) 1339 | throw "vec or dic" + ERROR.IS_UNDEFINED_OR_NULL; 1340 | 1341 | //バリデーション 1342 | if(dic.rows != mat.rows * mat.cols) 1343 | throw "辞書行列とmatの大きさが合っていません"; 1344 | 1345 | if(cvUndefinedOrNull(cvTermCriteria)) 1346 | cvTermCriteria = new CvTermCriteria(); 1347 | 1348 | if(cvUndefinedOrNull(eigenTermCriteria)) 1349 | eigenTermCriteria = cvTermCriteria; 1350 | 1351 | //係数ベクトル 1352 | rtn = cvCreateMat(vec.rows, 1); 1353 | for(var i = 0 ; i < rtn.rows ; rtn.vals[i++] = 0); 1354 | 1355 | //係数ベクトルに追加されたdicのindex 1356 | var support = new Array(); 1357 | 1358 | //選択辞書 1359 | var selectdic = cvCreateMat(dic.rows, 0); 1360 | 1361 | //残差ベクトル 1362 | var residualError = cvmCopy(vec); 1363 | 1364 | //仮の係数ベクトル 1365 | var tmpVec = cvmCopy(rtn); 1366 | 1367 | var isError = true; 1368 | for(var times = 0 ; times < dic.cols ; times++){ 1369 | var maxIndex = -1; 1370 | var maxDist = -1; 1371 | 1372 | //残差ベクトルとの内積が最も大きくなる辞書内の縦ベクトルのindexを探索する 1373 | for(var dicIndex = 0 ; dicIndex < dic.cols ; dicIndex++){ 1374 | //すでに係数ベクトルに存在するindexなら飛ばす 1375 | if(support.indexOf(dicIndex) != -1) 1376 | continue; 1377 | 1378 | //内積 1379 | var dist = 0; 1380 | for(var i = 0 ; i < dic.rows ; i++){ 1381 | dist += dic.vals[dicIndex + i * dic.cols] * residualError.vals[i]; 1382 | } 1383 | 1384 | 1385 | //最初の1回 1386 | if(maxIndex < 0){ 1387 | maxIndex = dicIndex; 1388 | maxDist = dist; 1389 | } 1390 | else if(maxDist < dist){ 1391 | maxIndex = dicIndex; 1392 | maxDist = dist; 1393 | } 1394 | } 1395 | 1396 | //サポートにインデックスを追加 1397 | support.push(maxIndex); 1398 | 1399 | //辞書の更新 1400 | selectdic = cvmInsertCol(selectdic, dic, maxIndex); 1401 | 1402 | //係数の更新 1403 | var selectdicInv = cvmInverse(selectdic, eigenTermCriteria, CV_INV.SVD); 1404 | tmpVec = cvmMul(selectdicInv, vec); 1405 | 1406 | //残差の更新 1407 | residualError = cvmSub(cvmMul(selectdic, tmpVec), vec); 1408 | 1409 | //残差の大きさをベクトルの長さで割る 1410 | var norm = cvmNorm(residualError) / residualError.rows; 1411 | 1412 | if(norm < cvTermCriteria.eps){ 1413 | isError = false; 1414 | break; 1415 | } 1416 | } 1417 | if(isError){ 1418 | throw "全ての基底を辞書に登録しても残差が閾値より小さくなりません"; 1419 | } 1420 | 1421 | //係数ベクトルを辞書に合わせて入れ替える 1422 | for(var i = 0 ; i < support.length ; i++){ 1423 | rtn.vals[support[i]]=tmpVec.vals[i]; 1424 | } 1425 | } 1426 | catch(ex){ 1427 | alert("cvmOMP : " + ex); 1428 | } 1429 | 1430 | return rtn; 1431 | } 1432 | 1433 | //k-SVD法により辞書行列と係数行列を更新する 1434 | //入力 1435 | //signals cvMat型 ひとつの観測信号を縦ベクトルとして並べた行列 1436 | //dic cvMat型 更新前の辞書 1437 | //coess cvMat型 係数の縦ベクトルを並べた行列 dic.cols == coess.rows 1438 | //cvTermCriteria CvTermCriteria型 epsの値が基底ベクトルの値を0とする閾値と内部の特異値分解で使われる計算精度 1439 | //cvTermCriteriaDiff CvTermCriteria型 epsの値が復元信号と原信号の差の絶対値の総和の閾値 1440 | //出力 1441 | //[upDic, upCoess] 1442 | //upDic CvMat型 更新された辞書 1443 | //upCoess CvMat型 更新された係数ベクトルの行列 1444 | function cvmK_SVD(signals, dic, coess, cvTermCriteria, cvTermCriteriaDiff){ 1445 | var upDic = null; 1446 | var upCoess = null; 1447 | try{ 1448 | var eps2 = cvTermCriteriaDiff.eps * cvTermCriteriaDiff.eps; 1449 | var k = 0; 1450 | //k番目の基底を更新する 1451 | for(; k < dic.cols ; k++){ 1452 | //coessのk行目から閾値以上の値をもつindexを抜き出す 1453 | var indexs = new Array(); 1454 | for(var i = 0 ; i < coess.cols ; i++){ 1455 | if(Math.abs(coess.vals[i + k * coess.cols]) > cvTermCriteria.eps){ 1456 | indexs.push(i); 1457 | } 1458 | } 1459 | 1460 | //辞書更新用のオメガ行列を生成する 1461 | var omega = cvCreateMat(dic.rows, indexs.length); 1462 | for(var i = 0 ; i < omega.rows * omega.cols ; omega.vals[i++] = 0); 1463 | for(var i = 0 ; i < indexs.length ; i++){ 1464 | omega.vals[i + indexs[i] * omega.cols] = 1; 1465 | } 1466 | 1467 | //係数行列から必要な部分だけ抜き出す 1468 | var ncoess = cvmMul(coess, omega); 1469 | 1470 | //元の信号から、辞書行列からk列目の縦ベクトルと、係数行列からk行目の横ベクトルを省いた行列同士の掛け算を引いた行列 1471 | //つまり辞書からk列目のベクトルを省いた時に元の信号との誤差を求める 1472 | var ek = cvCreateMat(dic.rows, dic.cols); 1473 | for(var i = 0 ; i < dic.rows ; i++){ 1474 | for(var j = 0; j < dic.cols ; j++){ 1475 | var val = 0; 1476 | for(var x = 0 ; x < dic.cols ; x++){ 1477 | if(x == k) continue; 1478 | val += dic.vals[x + i * dic.cols] * coess.vals[j + x * coess.cols]; 1479 | } 1480 | ek.vals[j + i * ek.cols] = signals.vals[j + i * signals.cols] - val; 1481 | } 1482 | } 1483 | 1484 | var ekOmega = cvmMul(ek, omega); 1485 | 1486 | //ekOmegaを特異値分解することで誤差を最小にするための行列を求める 1487 | var svd = cvmSVD(ekOmega, cvTermCriteria); 1488 | var w = svd[0]; 1489 | var left = svd[1]; 1490 | var right = svd[2]; 1491 | 1492 | 1493 | //辞書行列と係数行列のk列目の縦ベクトルを更新する 1494 | for(var i = 0 ; i < dic.rows ; i++){ 1495 | dic.vals[k + i * dic.cols] = left.vals[i * left.cols]; 1496 | } 1497 | for(var i = 0 ; i < indexs.length ; i++){ 1498 | coess.vals[indexs[i] + k * coess.cols] = right.vals[i * right.cols]; 1499 | } 1500 | 1501 | //復元画像との差分 1502 | var fukugen = cvmMul(dic, coess); 1503 | var sub = cvmSub(signals, fukugen); 1504 | 1505 | //差分画像の総和 1506 | var sum = 0; 1507 | for(var i = 0 ; i < sub.rows ; i++){ 1508 | for(var j = 0 ; j < sub.cols ; j++){ 1509 | sum += sub.vals[j + i * sub.cols] * sub.vals[j + i * sub.cols]; 1510 | } 1511 | } 1512 | 1513 | //閾値より小さければループを抜ける 1514 | if(sum < eps2){ 1515 | k++; 1516 | break; 1517 | } 1518 | } 1519 | 1520 | //新しい辞書と係数行列へ代入 1521 | upDic = cvCreateMat(dic.rows, k); 1522 | upCoess = cvCreateMat(k, coess.cols); 1523 | for(var i = 0 ; i < upDic.rows; i++){ 1524 | for(var j = 0 ; j < upDic.cols; j++){ 1525 | upDic.vals[j + i * upDic.cols] = dic.vals[j + i * dic.cols] 1526 | upCoess.vals[i + j * upCoess.cols] = coess.vals[i + j * coess.cols]; 1527 | } 1528 | } 1529 | } 1530 | catch(ex){ 1531 | alert("cvmK_SVD : " + ex); 1532 | } 1533 | 1534 | return [upDic, upCoess]; 1535 | } 1536 | 1537 | 1538 | 1539 | //row行cols列の疎行列を作る 1540 | //入力 1541 | //rows 整数 (y座標) 1542 | //cols 整数 (x座標) 1543 | //出力 1544 | //CvMat型 1545 | //備考 1546 | //内部のvalsは{row:row, col:col, value:value}オブジェクトの配列 1547 | //valsの座標以外は全て0を意味する 1548 | function cvCreateSparseMat(rows, cols){ 1549 | var rtn = new CvSparseMat(); 1550 | rtn.rows = rows; 1551 | rtn.cols = cols; 1552 | rtn.vals = new Array(); 1553 | 1554 | return rtn; 1555 | } 1556 | 1557 | //スパース行列に値を代入(基本的にスパース行列へ値を代入するにはこのメソッドを使う) 1558 | //入力 1559 | //smat CvSparseMat型 値が追加/変更されるスパース行列 1560 | //row int型 値を追加/変更するrow座標 1561 | //col int型 値を追加/変更するcol座標 1562 | //value double 型 追加/変更する値 1563 | function cvSparseMatSet(smat, row, col, value){ 1564 | try{ 1565 | if(cvUndefinedOrNull(smat) || cvUndefinedOrNull(value)|| 1566 | cvUndefinedOrNull(row) || cvUndefinedOrNull(col)) 1567 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 1568 | 1569 | if(smat.rows - 1 < row || smat.cols - 1 < col || 1570 | row < 0 || col < 0) 1571 | throw "引数の値が不正です"; 1572 | //変更 1573 | for(var i = 0 ; i < smat.vals.length ; i++){ 1574 | if(smat.vals[i].row == row && smat.vals[i].col == col){ 1575 | smat.vals[i].value = value; 1576 | return; 1577 | } 1578 | } 1579 | 1580 | //追記 1581 | smat.vals.push({row:row, col:col, value:value}); 1582 | } 1583 | catch(ex){ 1584 | alert("cvSparseMatset : " + ex); 1585 | } 1586 | } 1587 | 1588 | //チャンネルを合成する 1589 | //入力 1590 | //src0 IplImage型 dstの0チャンネルに合成される 1591 | //src1 IplImage型 dstの1チャンネルに合成される 1592 | //src2 IplImage型 dstの2チャンネルに合成される 1593 | //src3 IplImage型 dstの3チャンネルに合成される 1594 | //dst IplImage型 合成した画像 1595 | //出力 1596 | //なし 1597 | //解説 1598 | //各srcの0チャンネルの値が合成される 1599 | function cvMerge(src0, src1, src2, src3, dst){ 1600 | try{ 1601 | if(cvUndefinedOrNull(src0) || cvUndefinedOrNull(src1) || 1602 | cvUndefinedOrNull(src2) || cvUndefinedOrNull(src3) || cvUndefinedOrNull(dst) ) 1603 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 1604 | if(dst.width != src0.width || dst.width != src1.width || 1605 | dst.width != src2.width || dst.width != src3.width || 1606 | dst.height != src0.height || dst.height != src1.height || 1607 | dst.height != src2.height || dst.height != src3.height) 1608 | throw "IplImageの大きさを統一してください"; 1609 | 1610 | for(var c = 0 ; c < CHANNELS ; c++){ 1611 | var src; 1612 | switch(c){ 1613 | case 0 : src = src0; break; 1614 | case 1 : src = src1; break; 1615 | case 2 : src = src2; break; 1616 | case 3 : src = src3; break; 1617 | } 1618 | 1619 | for(var i = 0 ; i < src.height ; i++){ 1620 | var is = i * src.width * CHANNELS; 1621 | var js = 0; 1622 | for(var j = 0 ; j < src.width ; j++){ 1623 | dst.RGBA[c + js + is] = src.RGBA[js + is]; 1624 | js += CHANNELS; 1625 | } 1626 | } 1627 | } 1628 | } 1629 | catch(ex){ 1630 | alert("cvMerge : " + ex); 1631 | } 1632 | } 1633 | 1634 | //チャンネルを分割する 1635 | //入力 1636 | //src IplImage型 原画像 1637 | //dst0 IplImage型 srcのチャンネル0が代入される 1638 | //dst1 IplImage型 srcのチャンネル1が代入される 1639 | //dst2 IplImage型 srcのチャンネル2が代入される 1640 | //dst3 IplImage型 srcのチャンネル3が代入される 1641 | //出力 1642 | //なし 1643 | //解説 1644 | //分割されたチャンネルは各dstの0~3チャンネル全てに代入される 1645 | function cvSplit(src, dst0, dst1, dst2, dst3){ 1646 | try{ 1647 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(dst0) || 1648 | cvUndefinedOrNull(dst1) || cvUndefinedOrNull(dst2) || cvUndefinedOrNull(dst3) ) 1649 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 1650 | if(src.width != dst0.width || src.width != dst1.width || 1651 | src.width != dst2.width || src.width != dst3.width || 1652 | src.height != dst0.height || src.height != dst1.height || 1653 | src.height != dst2.height || src.height != dst3.height) 1654 | throw "IplImageの大きさを統一してください"; 1655 | 1656 | for(var c = 0 ; c < CHANNELS ; c++){ 1657 | var dst; 1658 | switch(c){ 1659 | case 0 : dst = dst0; break; 1660 | case 1 : dst = dst1; break; 1661 | case 2 : dst = dst2; break; 1662 | case 3 : dst = dst3; break; 1663 | } 1664 | 1665 | for(var i = 0 ; i < src.height ; i++){ 1666 | var is = i * src.width * CHANNELS; 1667 | var js = 0; 1668 | for(var j = 0 ; j < src.width ; j++){ 1669 | dst.RGBA[js + is] = src.RGBA[c + js + is]; 1670 | dst.RGBA[1 + js + is] = src.RGBA[c + js + is]; 1671 | dst.RGBA[2 + js + is] = src.RGBA[c + js + is]; 1672 | dst.RGBA[3 + js + is] = 255; 1673 | js += CHANNELS; 1674 | } 1675 | } 1676 | } 1677 | } 1678 | catch(ex){ 1679 | alert("cvSplit : " + ex); 1680 | } 1681 | } 1682 | 1683 | 1684 | //最大値と最小値とその座標を求める 1685 | //入力 1686 | //src IplImage型 計算対象となる画像 1687 | //min_val 数値型の配列 要素数4 RGB表色系ならばr,g,b,aの最小値が入る 1688 | //max_val 数値型の配列 要素数4 RGB表色系ならばr,g,b,aの最大値が入る 1689 | //min_locs CvPoint型の配列 要素数4 RGB表色系ならばr,g,b,aの最小値のピクセルの座標が入る 1690 | //max_locs CvPoint型の配列 要素数4 RGB表色系ならばr,g,b,aの最大値のピクセルの座標が入る 1691 | //mask IplImage型 0か255のマスク画像 省略可 1692 | //出力 1693 | //なし 1694 | function cvMinMaxLoc(src, min_val, max_val, min_locs, max_locs, mask){ 1695 | 1696 | try{ 1697 | if(cvUndefinedOrNull(src) || 1698 | cvUndefinedOrNull(min_val) || cvUndefinedOrNull(max_val) || 1699 | cvUndefinedOrNull(min_locs) || cvUndefinedOrNull(max_locs)) 1700 | throw "src or min_val or max_val or min_locs or max_locs " + ERROR.IS_UNDEFINED_OR_NULL; 1701 | for(var i = 0 ; i < min_locs.length ; i++) 1702 | if(cvUndefinedOrNull(min_locs[i])) throw "min_locs[" + i + "]" + ERROR.IS_UNDEFINED_OR_NULL; 1703 | for(var i = 0 ; i < max_locs.length ; i++) 1704 | if(cvUndefinedOrNull(max_locs[i])) throw "max_locs[" + i + "]" + ERROR.IS_UNDEFINED_OR_NULL; 1705 | 1706 | if(cvUndefinedOrNull(mask)) mask = 0; 1707 | if(mask != 0) throw "mask は現在サポートされていません"; 1708 | 1709 | for(var c = 0 ; c < CHANNELS ; c++){ 1710 | min_val[c] = src.RGBA[c]; 1711 | max_val[c] = src.RGBA[c]; 1712 | min_locs[c].x = 0 ; 1713 | min_locs[c].y = 0; 1714 | max_locs[c].x = 0 ; 1715 | max_locs[c].y = 0; 1716 | for(var i = 0 ; i < src.height ; i++){ 1717 | for(var j = 0 ; j < src.width ; j++){ 1718 | if(src.RGBA[c + (j + i * src.width) * CHANNELS] < min_val[c]){ 1719 | min_val[c] = src.RGBA[c + (j + i * src.width) * CHANNELS]; 1720 | min_locs[c].x = j; 1721 | min_locs[c].y = i; 1722 | } 1723 | if(src.RGBA[c + (j + i * src.width) * CHANNELS] > max_val[c]){ 1724 | max_val[c] = src.RGBA[c + (j + i * src.width) * CHANNELS]; 1725 | max_locs[c].x = j; 1726 | max_locs[c].y = i; 1727 | } 1728 | } 1729 | } 1730 | } 1731 | } 1732 | catch(ex){ 1733 | alert("cvMinMaxLoc : " + ex); 1734 | } 1735 | } 1736 | 1737 | //画像の画素の合計値 1738 | //入力 1739 | //src IplImage型 計算対象となる画像 1740 | //出力 1741 | //CvScalar型 RGB表色系ならr,g,b,aの結果が代入されている 1742 | function cvSum(src){ 1743 | var rtn = null; 1744 | try{ 1745 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 1746 | 1747 | rtn = new CvScalar(); 1748 | 1749 | for(var k = 0 ; k < rtn.length ; rtn[k++] = 0); 1750 | 1751 | for(var i = 0 ; i < src.height ; i++){ 1752 | for(var j = 0 ; j < src.width ; j++){ 1753 | for(var c = 0 ; c < CHANNELS ; c++) 1754 | rtn[c] = src.RGBA[c + (j + i * src.width) * CHANNELS]; 1755 | } 1756 | } 1757 | } 1758 | catch(ex){ 1759 | alert("cvSum : " + ex); 1760 | } 1761 | 1762 | return rtn; 1763 | } 1764 | 1765 | //画像の画素の平均値 1766 | //入力 1767 | //src IplImage型 計算対象となる画像 1768 | //mask IplImage型 0か255のマスク画像 省略可 1769 | //出力 1770 | //CvScalar型 RGB表色系ならr,g,b,aの結果が代入されている 1771 | function cvAvg(src, mask){ 1772 | var rtn = null; 1773 | try{ 1774 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 1775 | if(cvUndefinedOrNull(mask)) mask = 0; 1776 | if(mask != 0) throw "mask は現在サポートされていません"; 1777 | 1778 | rtn = cvSum(src); 1779 | var len = src.width * src.height; 1780 | 1781 | for(var k = 0 ; k < rtn.length ; rtn[k++] /= len); 1782 | 1783 | } 1784 | catch(ex){ 1785 | alert("cvAvg : " + ex); 1786 | } 1787 | 1788 | return rtn; 1789 | } 1790 | 1791 | //画像の画素の平均値と分散を求める 1792 | //入力 1793 | //src IplImage型 計算対象となる画像 1794 | //mean CvScalar型 平均値が入る RGB表色系ならr,g,b,aの結果が代入されている 1795 | //vrn CvScalar型 分散が入る RGB表色系ならr,g,b,aの結果が代入されている 1796 | //mask IplImage型 0か255のマスク画像 省略可 1797 | //出力 1798 | //なし 1799 | function cvAvgVrn(src, mean, vrn, mask){ 1800 | try{ 1801 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(mean) || cvUndefinedOrNull(vrn)) 1802 | throw "src or mean or vrn" + ERROR.IS_UNDEFINED_OR_NULL; 1803 | if(cvUndefinedOrNull(mask)) mask = 0; 1804 | if(mask != 0) throw "mask は現在サポートされていません"; 1805 | 1806 | var avg = cvAvg(src); 1807 | for(var c = 0 ; c < CHANNELS ; c++){ 1808 | mean[c] = avg[c]; 1809 | vrn[c] = 0; 1810 | var len = src.width * src.height; 1811 | for(var i = 0 ; i < src.height ; i++){ 1812 | for(var j = 0 ; j < src.width ; j++){ 1813 | var a = src.RGBA[c + (j + i * src.width) * CHANNELS] - mean[c]; 1814 | vrn[c] += a * a; 1815 | } 1816 | } 1817 | vrn[c] /= len; 1818 | } 1819 | } 1820 | catch(ex){ 1821 | alert("cvAvgVrn : " + ex); 1822 | } 1823 | } 1824 | 1825 | //画像の画素の平均値と標準偏差を求める 1826 | //入力 1827 | //src IplImage型 計算対象となる画像 1828 | //mean CvScalar型 平均値が入る RGB表色系ならr,g,b,aの結果が代入されている 1829 | //vrn CvScalar型 標準偏差が入る RGB表色系ならr,g,b,aの結果が代入されている 1830 | //mask IplImage型 0か255のマスク画像 省略可 1831 | //出力 1832 | //なし 1833 | function cvAvgSdv(src, mean, std, mask){ 1834 | cvAvgVrn(src, mean, std, mask); 1835 | for(var k = 0 ; k < std.length ; k++) 1836 | std[k] = Math.sqrt(std[k]); 1837 | } 1838 | 1839 | //画像の複製 1840 | //入力 1841 | //src IplImage型 複製される画像 1842 | //出力 1843 | //IplImage型 複製された画像 1844 | function cvCloneImage(src){ 1845 | var dst = null; 1846 | 1847 | try{ 1848 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 1849 | dst = cvCreateImage(src.width, src.height); 1850 | cvCopy(src, dst); 1851 | } 1852 | catch(ex){ 1853 | alert("cvCloneImage : " + ex); 1854 | } 1855 | 1856 | return dst; 1857 | } 1858 | 1859 | //画像の画素のコピー 1860 | //入力 1861 | //src IplImage型 画素を複製する画像 1862 | //dst IplImage型 複製された画素の画像 1863 | //出力 1864 | //なし 1865 | function cvCopy(src, dst){ 1866 | try{ 1867 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(dst)) throw "src or dst" + ERROR.IS_UNDEFINED_OR_NULL; 1868 | 1869 | for(var i = 0 ; i < src.height ; i++){ 1870 | var is = i * src.width * CHANNELS; 1871 | var js = 0; 1872 | for(var j = 0 ; j < src.width ; j++){ 1873 | for(var c = 0 ; c < CHANNELS ; c++) 1874 | dst.RGBA[c + js + is] = src.RGBA[c + js + is]; 1875 | js += CHANNELS; 1876 | } 1877 | } 1878 | } 1879 | catch(ex){ 1880 | alert("cvCopy : " + ex); 1881 | } 1882 | } 1883 | 1884 | //ルックアップテーブルに従って画素を変換 1885 | //入力 1886 | //src IplImage型 原画像 1887 | //dst IplImage型 画素を変換された後の画像 1888 | //lut 整数の配列 長さが256の整数配列 0~255の値が1つずつ代入されている 1889 | //color 整数 画像のどの色を変換するか決める値 0~2 1890 | //出力 1891 | //なし 1892 | function cvLUT(src, dst, lut, color){ 1893 | try{ 1894 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(dst) || cvUndefinedOrNull(color)) 1895 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 1896 | 1897 | for(var i = 0 ; i < src.height ; i++){ 1898 | for(var j = 0 ; j < src.width ; j++){ 1899 | var v = src.RGBA[color + (j + i * src.width) * CHANNELS]; 1900 | dst.RGBA[color + (j + i * src.width) * CHANNELS] = lut[v]; 1901 | } 1902 | } 1903 | } 1904 | catch(e){ 1905 | alert("cvLUT : " + ex); 1906 | } 1907 | } 1908 | 1909 | //画像の加算 1910 | //全画素に対して加算が行われる 1911 | //入力 1912 | //src1 IplImage型 ひとつめの画像 1913 | //src2 IplImage型 ひとつめの画像 1914 | //dst IplImage型 src1とsrc2を加算した結果 1915 | //出力 1916 | //なし 1917 | function cvAdd(src1, src2, dst){ 1918 | try{ 1919 | cvFourArithmeticOperations(src1, src2, dst, FOUR_ARITHMETIC.ADD); 1920 | } 1921 | catch(ex){ 1922 | alert("cvAdd : " + ex); 1923 | } 1924 | } 1925 | 1926 | //画像の減算 1927 | //全画素に対して減算が行われる 1928 | //入力 1929 | //src1 IplImage型 ひとつめの画像 1930 | //src2 IplImage型 ひとつめの画像 1931 | //dst IplImage型 src1とsrc2を減算した結果 1932 | //出力 1933 | //なし 1934 | function cvSub(src1, src2, dst){ 1935 | try{ 1936 | cvFourArithmeticOperations(src1, src2, dst, FOUR_ARITHMETIC.SUB); 1937 | } 1938 | catch(ex){ 1939 | alert("cvSub : " + ex); 1940 | } 1941 | } 1942 | 1943 | //画像のかけ算 1944 | //全画素に対してかけ算が行われる 1945 | //入力 1946 | //src1 IplImage型 ひとつめの画像 1947 | //src2 IplImage型 ひとつめの画像 1948 | //dst IplImage型 src1とsrc2を割算した結果 1949 | //出力 1950 | //なし 1951 | function cvMul(src1, src2, dst){ 1952 | try{ 1953 | cvFourArithmeticOperations(src1, src2, dst, FOUR_ARITHMETIC.MUL); 1954 | } 1955 | catch(ex){ 1956 | alert("cvMul : " + ex); 1957 | } 1958 | } 1959 | 1960 | //画像の割り算 1961 | //全画素に対して割り算が行われる 1962 | //入力 1963 | //src1 IplImage型 ひとつめの画像 1964 | //src2 IplImage型 ひとつめの画像 1965 | //dst IplImage型 src1とsrc2を掛け算した結果 1966 | //出力 1967 | //なし 1968 | function cvDiv(src1, src2, dst){ 1969 | try{ 1970 | cvFourArithmeticOperations(src1, src2, dst, FOUR_ARITHMETIC.DIV); 1971 | } 1972 | catch(ex){ 1973 | alert("cvDiv : " + ex); 1974 | } 1975 | } 1976 | 1977 | //画素を絶対値にする 1978 | //入力 1979 | //src IplImage型 原画像 cvSobel等で画素値がマイナスのものを想定 1980 | //dst IplImage型 画素が絶対値化された画像 1981 | //出力 1982 | //なし 1983 | function cvConvertScaleAbs(src, dst){ 1984 | try{ 1985 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(dst)) throw "src or dst" + ERROR.IS_UNDEFINED_OR_NULL; 1986 | if(src.width != dst.width || src.height != dst.height) throw ERROR.DIFFERENT_SIZE; 1987 | 1988 | for(var i = 0 ; i < dst.height ; i++){ 1989 | for(var j = 0; j < dst.width ; j++){ 1990 | for(var c = 0 ; c < CHANNELS ; c++){ 1991 | dst.RGBA[c + (j + i * dst.width) * CHANNELS] = Math.abs(src.RGBA[c + (j + i * dst.width) * CHANNELS]); 1992 | } 1993 | } 1994 | } 1995 | } 1996 | catch(ex){ 1997 | alert("cvConvertScaleAbs : " + ex); 1998 | } 1999 | } 2000 | 2001 | //全座標に色を代入 2002 | //入力 2003 | //src IplImage型 色が代入される画像 2004 | //color CvScalar型 代入する色 2005 | //出力 2006 | //なし 2007 | function cvSet(src, color){ 2008 | try{ 2009 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(color)) 2010 | throw "src or color" + ERROR.IS_UNDEFINED_OR_NULL; 2011 | for(var i = 0 ; i < src.height ; i++){ 2012 | for(var j = 0 ; j < src.width ; j++){ 2013 | src.RGBA[(j + i * src.width) * CHANNELS] = color.val[0]; 2014 | src.RGBA[1 + (j + i * src.width) * CHANNELS] = color.val[1]; 2015 | src.RGBA[2 + (j + i * src.width) * CHANNELS] = color.val[2]; 2016 | src.RGBA[3 + (j + i * src.width) * CHANNELS] = color.val[3]; 2017 | } 2018 | } 2019 | } 2020 | catch(ex){ 2021 | alert("cvSet : " + ex); 2022 | } 2023 | } 2024 | 2025 | //全座標にゼロを代入 2026 | //入力 2027 | //src IplImage型 ゼロが代入される画像 2028 | //出力 2029 | //なし 2030 | function cvZero(src){ 2031 | try{ 2032 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 2033 | for(var i = 0 ; i < src.height ; i++){ 2034 | var is = i * src.width * CHANNELS; 2035 | var js = 0; 2036 | for(var j = 0 ; j < src.width ; j++){ 2037 | for(var c = 0 ; c < CHANNELS - 1 ; src.RGBA[c++ + js + is] = 0); 2038 | src.RGBA[3 + js + is] = 255; 2039 | js+= CHANNELS; 2040 | } 2041 | } 2042 | } 2043 | catch(ex){ 2044 | alert("cvZero : " + ex); 2045 | } 2046 | } 2047 | 2048 | //全座標に色を代入 2049 | //入力 2050 | //src IplImage型 色が代入される画像 2051 | //c1 整数 ひとつめの色 (RGB表色系ならR) 2052 | //c2 整数 ふたつめの色 (RGB表色系ならG) 2053 | //c3 整数 みっつめの色 (RGB表色系ならB) 2054 | //a 整数 アルファ値 2055 | //出力 2056 | //なし 2057 | function cvSetRGBA(src, c1, c2, c3, a){ 2058 | try{ 2059 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 2060 | if(cvUndefinedOrNull(c1)) c1 = 255; 2061 | if(cvUndefinedOrNull(c2)) c2 = 255; 2062 | if(cvUndefinedOrNull(c3)) c3 = 255; 2063 | if(cvUndefinedOrNull(a)) a = 255; 2064 | 2065 | var color = new CvScalar(); 2066 | color.val[0] = c1; 2067 | color.val[1] = c2; 2068 | color.val[2] = c3; 2069 | color.val[3] = a; 2070 | 2071 | cvSet(src, color); 2072 | } 2073 | catch(ex){ 2074 | alert("cvSetRGBA : " + ex); 2075 | } 2076 | } 2077 | 2078 | //画像の四則演算 2079 | //全画素に対して四則演算が行われる for(var cvSub cvMul cvDivで呼び出されることを想定 2080 | //入力 2081 | //src1 IplImage型 ひとつめの画像 2082 | //src2 IplImage型 ひとつめの画像 2083 | //dst IplImage型 src1とsrc2をfour_arithmeticに従って演算する 2084 | //four_arithmetic FOUR_ARITHMETIC 四則演算 2085 | //出力 2086 | //なし 2087 | function cvFourArithmeticOperations(src1, src2, dst, four_arithmetic){ 2088 | try{ 2089 | if(cvUndefinedOrNull(src1) || cvUndefinedOrNull(src2) || cvUndefinedOrNull(dst) || cvUndefinedOrNull(four_arithmetic)) 2090 | throw "src1 or src2 or dst or four_arithmetic" + ERROR.IS_UNDEFINED_OR_NULL; 2091 | if(src1.width != src2.width || src1.height != src2.height || 2092 | src1.width != dst.width || src1.height != dst.height) throw ERROR.DIFFERENT_SIZE; 2093 | 2094 | for(var i = 0 ; i < dst.height ; i++){ 2095 | for(var j = 0; j < dst.width ; j++){ 2096 | for(var c = 0 ; c < CHANNELS ; c++){ 2097 | var newValue; 2098 | switch(four_arithmetic){ 2099 | case FOUR_ARITHMETIC.ADD: 2100 | newValue = src1.RGBA[c + (j + i * dst.width) * CHANNELS] + src2.RGBA[c + (j + i * dst.width) * CHANNELS]; 2101 | break; 2102 | case FOUR_ARITHMETIC.SUB: 2103 | newValue = src1.RGBA[c + (j + i * dst.width) * CHANNELS] - src2.RGBA[c + (j + i * dst.width) * CHANNELS]; 2104 | break; 2105 | case FOUR_ARITHMETIC.MUL: 2106 | newValue = src1.RGBA[c + (j + i * dst.width) * CHANNELS] * src2.RGBA[c + (j + i * dst.width) * CHANNELS]; 2107 | break; 2108 | case FOUR_ARITHMETIC.DIV: 2109 | newValue = src1.RGBA[c + (j + i * dst.width) * CHANNELS] / src2.RGBA[c + (j + i * dst.width) * CHANNELS]; 2110 | break; 2111 | default: 2112 | throw "four_arithmetic" + ERROR.SWITCH_VALUE; 2113 | return; 2114 | break; 2115 | } 2116 | 2117 | dst.RGBA[c + (j + i * dst.width) * CHANNELS] = newValue; 2118 | } 2119 | } 2120 | } 2121 | } 2122 | catch(ex){ 2123 | throw ex; 2124 | } 2125 | } 2126 | 2127 | //画像のゼロでない画素数を数える 2128 | //入力 2129 | //src IplImage型 計算対象となる画像 2130 | //出力 2131 | //CvScalar型 RGB表色系ならr,g,b,aの結果が代入されている 2132 | function cvCountNonZero(src){ 2133 | var rtn = null; 2134 | try{ 2135 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 2136 | 2137 | rtn = new CvScalar(); 2138 | for(var k = 0 ; k < rtn.length ; rtn.val[k++] = 0); 2139 | 2140 | for(var i = 0 ; i < src.height ; i++){ 2141 | for(var j = 0 ; j < src.width ; j++){ 2142 | for(var c = 0 ; c < CHANNELS ; c++){ 2143 | if(src.RGBA[c + (j + i * src.width) * CHANNELS] != 0) 2144 | rtn.val[c]++; 2145 | } 2146 | } 2147 | } 2148 | } 2149 | catch(ex){ 2150 | alert("cvCountNonZero : " + ex); 2151 | } 2152 | 2153 | return rtn; 2154 | } 2155 | 2156 | 2157 | //FFT or inverse FFT を行う 2158 | //入力 2159 | //src IplImage型 GRAY表色系を想定(RGB表色系ならRがFFTされる) ※解説参照 2160 | //isForward true/false trueなら順変換 falseなら逆変換 2161 | //出力 2162 | //なし 2163 | //解説 2164 | //srcのwidthとheight共に2のべき乗である必要がある 2165 | //計算結果は実数値が最初のチャンネル、虚数値がふたつめのチャンネルに代入される 2166 | function cvFFT(src, isForward){ 2167 | try{ 2168 | if(cvUndefinedOrNull(src)) throw "src" + ERROR.IS_UNDEFINED_OR_NULL; 2169 | if(cvUndefinedOrNull(isForward)) isForward = true; 2170 | if((src.width & (src.width - 1)) != 0 || 2171 | (src.height & (src.height - 1)) != 0) throw "srcのwidthとheightは2のべき乗にしてください"; 2172 | 2173 | //1次元変換 2174 | function oneLineFFT(ar, ai, isForward){ 2175 | var j, j1, j2; 2176 | var dr1, dr2, di1, di2, tr, ti; 2177 | 2178 | var iter = 0; 2179 | j = ar.length; 2180 | while((j /= 2) != 0) iter++; 2181 | 2182 | j = 1; 2183 | for(var i = 0; i < iter; i++) j *= 2; 2184 | 2185 | var w = (isForward ? Math.PI: -Math.PI) / ar.length; 2186 | var xp2 = ar.length; 2187 | for(var it = 0; it < iter; it++) 2188 | { 2189 | xp = xp2; 2190 | xp2 = Math.floor(xp2/2); 2191 | w *= 2; 2192 | for(var k = 0, i = - xp; k < xp2; i++) 2193 | { 2194 | var arg = w * k; 2195 | k++; 2196 | var wr = Math.cos(arg); 2197 | var wi = Math.sin(arg); 2198 | for(var j = xp; j <= ar.length; j += xp) 2199 | { 2200 | j1 = j + i; 2201 | j2 = j1 + xp2; 2202 | dr1 = ar[j1]; 2203 | dr2 = ar[j2]; 2204 | di1 = ai[j1]; 2205 | di2 = ai[j2]; 2206 | tr = dr1 - dr2; 2207 | ti = di1 - di2; 2208 | ar[j1] = dr1 + dr2; 2209 | ai[j1] = di1 + di2; 2210 | ar[j2] = tr * wr - ti * wi; 2211 | ai[j2] = ti * wr + tr * wi; 2212 | } 2213 | } 2214 | } 2215 | j = j1 = ar.length / 2; 2216 | j2 = ar.length - 1; 2217 | for(var i = 1; i < j2; i++) 2218 | { 2219 | if(i < j) 2220 | { 2221 | w = ar[i]; 2222 | ar[i] = ar[j]; 2223 | ar[j] = w; 2224 | w = ai[i]; 2225 | ai[i] = ai[j]; 2226 | ai[j] = w; 2227 | } 2228 | k = j1; 2229 | while(k <= j) 2230 | { 2231 | j -= k; 2232 | k /= 2; 2233 | } 2234 | j += k; 2235 | } 2236 | if(!isForward) return; 2237 | w = 1. / ar.length; 2238 | for(var i = 0; i < ar.length; i++) 2239 | { 2240 | ar[i] *= w; 2241 | ai[i] *= w; 2242 | } 2243 | return; 2244 | } 2245 | 2246 | //横方向 2247 | var ar = new Array(src.width); 2248 | var ai = new Array(src.width); 2249 | for(var i = 0 ; i < src.height ; i++){ 2250 | var is = i * src.width * CHANNELS; 2251 | var js = 0; 2252 | for(var j = 0 ; j < src.width ; j++){ 2253 | ar[j] = src.RGBA[js + is]; 2254 | ai[j] = src.RGBA[1 + js + is]; 2255 | js += CHANNELS; 2256 | } 2257 | oneLineFFT(ar, ai, isForward); 2258 | js = 0; 2259 | for(var j = 0 ; j < src.width ; j++){ 2260 | src.RGBA[js + is] = ar[j] ; 2261 | src.RGBA[1 + js + is] = ai[j] ; 2262 | js += CHANNELS; 2263 | } 2264 | } 2265 | 2266 | //縦方向 2267 | ar = new Array(src.height); 2268 | ai = new Array(src.height); 2269 | var schan = src.width * CHANNELS; 2270 | for(var j = 0 ; j < src.width ; j++){ 2271 | var js = j * CHANNELS; 2272 | var is = 0; 2273 | for(var i = 0 ; i < src.height ; i++){ 2274 | ar[i] = src.RGBA[js + is]; 2275 | ai[i] = src.RGBA[1 + js + is]; 2276 | is += schan; 2277 | } 2278 | oneLineFFT(ar, ai, isForward); 2279 | is = 0; 2280 | for(var i = 0 ; i < src.height ; i++){ 2281 | src.RGBA[js + is] = ar[j] ; 2282 | src.RGBA[1 + js + is] = ai[j] ; 2283 | is += schan; 2284 | } 2285 | } 2286 | } 2287 | catch(ex){ 2288 | alert("cvFFT : " + ex); 2289 | } 2290 | } 2291 | 2292 | //DFT 2293 | //入力 2294 | //src IplImage型 dftする画像 GRAY表色系を想定(RGB表色系ならRの数値だけで処理する) 2295 | //dst IplImage型 dftした結果が保存される RGB表色系ならRに実数 Gに虚数が代入される 2296 | //flags 2297 | //nonzero_rows 2298 | function cvDFT(src, dst, flags, nonzero_rows){ 2299 | try{ 2300 | if(cvUndefinedOrNull(src) || cvUndefinedOrNull(dst) || cvUndefinedOrNull(flags)) 2301 | throw "sizes or dst or flags" + ERROR.IS_UNDEFINED_OR_NULL; 2302 | if(cvUndefinedOrNull(nonzero_rows)) nonzero_rows = 0; 2303 | 2304 | var arg = (CV_DXT.FORWARD || CV_DXT.FORWARD_SCALE) ? 2305 | -2 * Math.PI / src.width : 2 * Math.PI / src.width; 2306 | 2307 | cvZero(dst); 2308 | 2309 | //横方向 2310 | for(var y = 0 ; y < dst.height ; y++){ 2311 | console.log(y); 2312 | for(var x = 0 ; x < dst.width ; x++){ 2313 | for(var i = 0; i < src.height ; i++){ 2314 | for(var j = 0 ; j < src.width ; j++){ 2315 | var freq = arg * x * j ; 2316 | var cos = Math.cos(freq); 2317 | var sin = Math.sin(freq); 2318 | dst.RGBA[(x + y * dst.width) * CHANNELS] += 2319 | src.RGBA[(j + i * src.width) * CHANNELS] * cos + 2320 | src.RGBA[1 + (j + i * src.width) * CHANNELS] * sin; 2321 | 2322 | dst.RGBA[1 + (x + y * dst.width) * CHANNELS] += 2323 | src.RGBA[1 + (j + i * src.width) * CHANNELS] * cos - 2324 | src.RGBA[(j + i * src.width) * CHANNELS] * sin; 2325 | } 2326 | } 2327 | } 2328 | } 2329 | 2330 | console.log("横終了"); 2331 | 2332 | //縦方向 2333 | for(var y = 0 ; y < dst.height ; y++){ 2334 | for(var x = 0 ; x < dst.width ; x++){ 2335 | for(var j = 0 ; j < src.width ; j++){ 2336 | for(var i = 0; i < src.height ; i++){ 2337 | var freq = arg * y * i ; 2338 | var cos = Math.cos(freq); 2339 | var sin = Math.sin(freq); 2340 | dst.RGBA[(x + y * dst.width) * CHANNELS] += 2341 | src.RGBA[(j + i * src.width) * CHANNELS] * cos + 2342 | src.RGBA[1 + (j + i * src.width) * CHANNELS] * sin; 2343 | 2344 | dst.RGBA[1 + (x + y * dst.width) * CHANNELS] += 2345 | src.RGBA[1 + (j + i * src.width) * CHANNELS] * cos - 2346 | src.RGBA[(j + i * src.width) * CHANNELS] * sin; 2347 | 2348 | } 2349 | } 2350 | } 2351 | } 2352 | 2353 | if(CV_DXT.FORWARD_SCALE || INVERSE_SCALE){ 2354 | var scale = Math.sqrt(1.0 / (dst.width * dst.height)); 2355 | for(var i = 0 ; i < dst.height ; i++){ 2356 | for(var j = 0 ; j < dst.width ; j++){ 2357 | dst.RGBA[(j + i * dst.width) * CHANNELS] /= scale; 2358 | dst.RGBA[1 + (j + i * dst.width) * CHANNELS] /= scale; 2359 | } 2360 | } 2361 | } 2362 | } 2363 | catch(ex){ 2364 | alert("cvDFT : " + ex); 2365 | } 2366 | } 2367 | 2368 | //undefinedまたはnullチェック 2369 | //入力 2370 | //value チェックされる入力 2371 | //出力 2372 | //true/false 2373 | function cvUndefinedOrNull(value){ 2374 | return (value === undefined || value === null) ? true : false; 2375 | } 2376 | 2377 | //IplImage型を生成する 2378 | //入力 2379 | //width 整数 生成するIplImageのwidth 2380 | //height 整数 生成するIplImageのheight 2381 | //出力 2382 | //IplImage 2383 | function cvCreateImage(width, height){ 2384 | var dst = null; 2385 | try{ 2386 | if(cvUndefinedOrNull(width) || cvUndefinedOrNull(height)) 2387 | throw "width or height" + ERROR.IS_UNDEFINED_OR_NULL; 2388 | else if(width <= 0 || height <= 0) 2389 | throw "width or height" + ERROR.ONLY_POSITIVE_NUMBER; 2390 | 2391 | dst = new IplImage(); 2392 | dst.canvas = document.createElement('canvas'); 2393 | dst.canvas.width = width; 2394 | dst.canvas.height = height; 2395 | if (cvUndefinedOrNull(dst.canvas)) throw 'canvas' + ERROR.IS_UNDEFINED_OR_NULL; 2396 | if (! dst.canvas.getContext) throw ERROR.NOT_GET_CONTEXT; 2397 | dst.height = dst.canvas.height; 2398 | dst.width = dst.canvas.width; 2399 | dst.imageData = dst.canvas.getContext("2d").getImageData(0, 0, dst.canvas.width, dst.canvas.height); 2400 | dst.RGBA = new Array(dst.width * dst.width * CHANNELS); 2401 | for(var i = 0 ; i < dst.height ; i++){ 2402 | var is = i * dst.width * CHANNELS; 2403 | var js = 0; 2404 | for(var j = 0 ; j < dst.width ; j++){ 2405 | for(var c = 0 ; c < CHANNELS - 1; dst.RGBA[c++ + js + is] = 0); 2406 | dst.RGBA[3 + js + is] = 255; 2407 | js += CHANNELS; 2408 | } 2409 | } 2410 | } 2411 | catch(ex){ 2412 | alert("cvCreateImage : " + ex); 2413 | } 2414 | 2415 | return dst; 2416 | } 2417 | 2418 | //CvMatの内容をdocumentに表示 2419 | function cvDWriteMatrix(ar, title){ 2420 | 2421 | //デフォルト値 2422 | if(typeof title !== 'undefined'){ 2423 | document.write(title + "
"); 2424 | } 2425 | 2426 | for(var i = 0; i < ar.rows ; i++){ 2427 | for(var j = 0; j < ar.cols ; j++){ 2428 | document.write(ar.vals[j + i * ar.cols] + ", "); 2429 | } 2430 | document.write("
"); 2431 | } 2432 | document.write("
"); 2433 | } 2434 | 2435 | //CvMatの内容をalertで表示 2436 | function cvAlertMat(src){ 2437 | try{ 2438 | var str = ""; 2439 | for(var i = 0 ; i < src.rows ; i++){ 2440 | for(var j = 0 ; j < src.cols; j++){ 2441 | str += src.vals[j + i * src.cols] + ", "; 2442 | } 2443 | str += "\n"; 2444 | } 2445 | alert(str); 2446 | } 2447 | catch(ex){ 2448 | alert("cvAlertMat : " + ex); 2449 | } 2450 | } 2451 | 2452 | //2次元ベクトルの角度と大きさを求めます 2453 | //入力 2454 | // xImage IplImage型 x座標の値(x方向の微分画像) 2455 | // yImage IplImage型 y座標の値(y方向の微分画像) 2456 | // magImage IplImage型 大きさの出力 xImageと同じサイズ 2457 | //angImage IplImage型 角度の出力 xImageと同じサイズ角度はラジアン (-PI から PI) あるいは度 (-180 から 180) で表される 2458 | //angleInDegrees bool型 角度の表記にラジアン(デフォルト),または度のどちらを用いるかを指定するフラグ trueでラジアン 2459 | //出力 2460 | //なし 2461 | function cvCartToPolar(xImage, yImage, magImage, angImage, angleInDegrees){ 2462 | try{ 2463 | if(cvUndefinedOrNull(xImage) || cvUndefinedOrNull(yImage) || 2464 | cvUndefinedOrNull(magImage) || cvUndefinedOrNull(angImage)) 2465 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 2466 | else if(xImage.width != yImage.width || yImage.width != magImage.width || magImage.width != angImage.width || 2467 | xImage.height != yImage.height || yImage.height != magImage.height || magImage.height != angImage.height) 2468 | throw ERROR.DIFFERENT_SIZE; 2469 | 2470 | if(cvUndefinedOrNull(angleInDegrees)) 2471 | angleInDegrees = false; 2472 | 2473 | for(var i = 0 ; i < xImage.height; i++){ 2474 | var p = i * magImage.width * CHANNELS ; 2475 | for(var j = 0 ; j < xImage.width; j++){ 2476 | var xI = xImage.RGBA[p]; 2477 | var yI = yImage.RGBA[p] 2478 | magImage.RGBA[p] = Math.sqrt(xI * xI + yI * yI); 2479 | angImage.RGBA[p] = Math.atan2(yI, xI); 2480 | if(angleInDegrees) angImage.RGBA[p] *= 180 / Math.PI; 2481 | p += CHANNELS ; 2482 | } 2483 | } 2484 | 2485 | 2486 | } 2487 | catch(ex){ 2488 | alert("cvCartToPolar : " + ex); 2489 | } 2490 | } 2491 | 2492 | -------------------------------------------------------------------------------- /module/highgui.js: -------------------------------------------------------------------------------- 1 | //IplImage型をimgタグに出力する 2 | //入力 3 | //imgId Id型 imgタグのId 4 | //iplImage IplImage型 imgに転送する画像 5 | //出力 6 | //なし 7 | function cvShowImage(imgId, iplImage){ 8 | try{ 9 | if(cvUndefinedOrNull(imgId) || cvUndefinedOrNull(iplImage)) 10 | throw "imgId or iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 11 | cvRGBA2ImageData(iplImage); 12 | if (iplImage.canvas.getContext) { 13 | 14 | iplImage.canvas.getContext("2d").putImageData(iplImage.imageData, 0, 0); 15 | var imgElement = document.getElementById(imgId); 16 | if(imgElement == null) throw imgId + ERROR.IS_UNDEFINED_OR_NULL; 17 | 18 | imgElement.width = iplImage.width; 19 | imgElement.height = iplImage.height; 20 | 21 | imgElement.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEHAAEALAAAAAABAAEAAAICTAEAOw=="; 22 | imgElement.onload = function(event){ 23 | imgElement.src = iplImage.canvas.toDataURL('image/jpeg'); 24 | }; 25 | } 26 | else throw ERROR.NOT_GET_CONTEXT; 27 | } 28 | catch(ex){ 29 | alert("cvShowImage : " + ex); 30 | } 31 | } 32 | 33 | //IplImage型をcanvasタグに出力する 34 | //入力 35 | //canvasId Id型 canvasタグのId 36 | //iplImage IplImage型 canvasに転送する画像 37 | //出力 38 | //なし 39 | function cvShowImageToCanvas(canvasId, iplImage){ 40 | try{ 41 | if(cvUndefinedOrNull(canvasId) || cvUndefinedOrNull(iplImage)) 42 | throw "canvasId or iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 43 | var canvasElement = document.getElementById(canvasId); 44 | cvShowImageToCanvasElement (canvasElement, iplImage); 45 | } 46 | catch(ex){ 47 | alert("cvShowImageToCanvas : " + ex); 48 | } 49 | } 50 | 51 | //IplImage型をcanvasエレメントに出力する 52 | //入力 53 | //canvasElement element型 canvasのエレメント 54 | //iplImage IplImage型 canvasに転送する画像 55 | //出力 56 | //なし 57 | function cvShowImageToCanvasElement(canvasElement, iplImage){ 58 | try{ 59 | if(cvUndefinedOrNull(canvasElement) || cvUndefinedOrNull(iplImage)) 60 | throw "canvasElement or iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 61 | 62 | cvRGBA2ImageData(iplImage); 63 | canvasElement.getContext("2d").putImageData(iplImage.imageData, 0, 0); 64 | } 65 | catch(ex){ 66 | alert("cvShowImageToCanvas : " + ex); 67 | } 68 | } -------------------------------------------------------------------------------- /module/imgcodecs.js: -------------------------------------------------------------------------------- 1 | //-------------------メソッド------------------ 2 | 3 | //cvLoadImageを呼び出す前に必要な前処理 4 | //htmlのinputタグのonClickで呼び出すことを想定 5 | //入力 6 | //event event型 発生したイベント 7 | //inputId Id型 イベントの発生元のId 8 | //出力 9 | //なし 10 | function cvLoadImagePre(event, inputId){ 11 | try{ 12 | if(cvUndefinedOrNull(event) || cvUndefinedOrNull(inputId)) 13 | throw "event or inputId" + ERROR.IS_UNDEFINED_OR_NULL; 14 | var dialog = document.getElementById(inputId); 15 | dialog.value = ""; 16 | } 17 | catch(ex){ 18 | alert("cvLoadImagePre : " + ex); 19 | } 20 | } 21 | 22 | //inputタグからiplImageに変換し、imgタグに出力する 23 | //htmlのinputタグのonchangeで呼び出すことを想定 24 | //入力 25 | //event event型 発生したイベント 26 | //imgId Id型 読み込んだ画像を表示させるimgタグのid 27 | //iplImage IplImage型 srcの値が代入される 28 | //maxSize 整数 srcの縦or横幅がこの値以上なら、この値となるように大きさを変換して代入される -1なら処理されない 省略可 29 | //出力 30 | //なし 31 | function cvLoadImage(event, imgId, iplImage, maxSize){ 32 | try{ 33 | if(cvUndefinedOrNull(event) || cvUndefinedOrNull(imgId) || cvUndefinedOrNull(iplImage)) 34 | throw "event or imgId or iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 35 | var file = event.target.files[0]; 36 | if (file){ 37 | cvLoadImageAtEventFile(file, imgId, iplImage, maxSize); 38 | event = null; 39 | } 40 | } 41 | catch(ex){ 42 | alert("cvLoadImage : " + ex); 43 | } 44 | } 45 | 46 | //inputタグから複数のiplImageに変換し、複数のimgタグに出力する 47 | //htmlのinputタグのonchangeで呼び出すことを想定 48 | //入力 49 | //event event型 発生したイベント 50 | //imgIds Id型の配列 読み込んだ画像を表示させるimgタグのid 51 | //iplImages IplImage型の配列 srcの値が代入される 52 | //maxSize 整数 srcの縦or横幅がこの値以上なら、この値となるように大きさを変換して代入される -1なら処理されない 省略可 53 | //出力 54 | //なし 55 | function cvLoadImages(event, imgIds, iplImages, maxSize) 56 | { 57 | try{ 58 | for(var i = 0 ; i < event.target.files.length ; i++){ 59 | var file = event.target.files[i]; 60 | if (file){ 61 | var imgId = imgIds[i]; 62 | var iplImage = iplImages[i]; 63 | cvLoadImageAtEventFile(file, imgId, iplImage, maxSize); 64 | } 65 | } 66 | } 67 | catch(ex){ 68 | alert("cvLoadImages : " + ex); 69 | } 70 | } 71 | 72 | //event.target.files配列の要素からiplImageに変換する 73 | //cvLoadImageかcvLoadImagesで呼び出すことを想定 74 | //入力 75 | //file file型 event.target.files配列の要素 76 | //imgId Id型 読み込んだ画像を表示させるimgタグのid 77 | //iplImage IplImage型 srcの値が代入される 78 | //maxSize 整数 srcの縦or横幅がこの値以上なら、この値となるように大きさを変換して代入される -1なら処理されない 省略可 79 | //出力 80 | //なし 81 | function cvLoadImageAtEventFile(file, imgId, iplImage, maxSize) 82 | { 83 | try{ 84 | if(cvUndefinedOrNull(maxSize)) maxSize = -1; 85 | var reader = new FileReader(); 86 | reader.readAsDataURL(file); 87 | reader.onload = function(event){ 88 | var imgElement = document.getElementById(imgId); 89 | imgElement.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEHAAEALAAAAAABAAEAAAICTAEAOw=="; 90 | imgElement.onload = function(){ 91 | imgElement.src = event.target.result; 92 | imgElement.onload = function(){ 93 | var originalSize = cvGetOriginalSizeAtImgElement(imgElement); 94 | var scale = 1; 95 | if(maxSize != -1 && (originalSize.width > maxSize || originalSize.height > maxSize)) 96 | scale = (originalSize.width > originalSize.height) ? 97 | maxSize / originalSize.width : maxSize / originalSize.height; 98 | imgElement.width = scale * originalSize.width; 99 | imgElement.height = scale * originalSize.height; 100 | iplImage.canvas = cvGetCanvasAtImgElement(imgElement); 101 | iplImage.width = iplImage.canvas.width; 102 | iplImage.height = iplImage.canvas.height; 103 | iplImage.RGBA = new Array(iplImage.width * iplImage.width * CHANNELS); 104 | iplImage.imageData = iplImage.canvas.getContext("2d").getImageData(0, 0, iplImage.canvas.width, iplImage.canvas.height); 105 | cvImageData2RGBA(iplImage); 106 | event = null; 107 | }; 108 | }; 109 | }; 110 | reader.onerror = function(event){ 111 | console.log(ERROR.NOT_READ_FILE); 112 | alert(ERROR.NOT_READ_FILE); 113 | // if (event.target.error.code == event.target.error.NOT_READABLE_ERR) { 114 | // alert(ERROR.NOT_READ_FILE); 115 | // } 116 | }; 117 | } 118 | catch(ex){ 119 | alert("cvLoadImageAtEventFile : " + ex); 120 | } 121 | } 122 | 123 | 124 | //inputタグからIplImage型に変換し、canvasタグに出力する 125 | //htmlのinputタグのonchangeで呼び出すことを想定 126 | //入力 127 | //event event型 発生したイベント 128 | //canvasId Id型 読み込んだ画像を表示させるcanvasタグのid 129 | //iplImage IplImage型 srcの値が代入される 130 | //maxSize 整数 srcの縦or横幅がこの値以上なら、この値となるように大きさを変換して代入される -1なら処理されない 省略可 131 | //出力 132 | //なし 133 | function cvLoadImageToCanvas(event, canvasId, iplImage, maxSize){ 134 | try{ 135 | if(cvUndefinedOrNull(event) || cvUndefinedOrNull(canvasId) || cvUndefinedOrNull(iplImage)) 136 | throw "event or canvasId or iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 137 | var file = event.target.files[0]; 138 | if (file){ 139 | cvLoadImageToCanvasAtEventFile(file, canvasId, iplImage, maxSize); 140 | } 141 | } 142 | catch(ex){ 143 | alert("cvLoadImageToCanvas : " + ex); 144 | } 145 | } 146 | 147 | //event.target.files配列の要素からiplImageに変換しcanvasタグに出力する 148 | //cvLoadImageToCanvasで呼び出すことを想定 149 | //入力 150 | //file file型 event.target.files配列の要素 151 | //canvasId Id型 読み込んだ画像を表示させるcanvasタグのid 152 | //iplImage IplImage型 srcの値が代入される 153 | //maxSize 整数 srcの縦or横幅がこの値以上なら、この値となるように大きさを変換して代入される -1なら処理されない 省略可 154 | //出力 155 | //なし 156 | function cvLoadImageToCanvasAtEventFile(file, canvasId, iplImage, maxSize) 157 | { 158 | try{ 159 | if(cvUndefinedOrNull(maxSize)) maxSize = -1; 160 | var reader = new FileReader(); 161 | reader.readAsDataURL(file); 162 | reader.onload = function(event){ 163 | var img = document.createElement('img'); 164 | img.src = event.target.result; 165 | var originalSize = cvGetOriginalSizeAtImgElement(img); 166 | var scale = 1; 167 | if(maxSize != -1 && (originalSize.width > maxSize || originalSize.height > maxSize)) 168 | scale = (originalSize.width > originalSize.height) ? 169 | maxSize / originalSize.width : maxSize / originalSize.height; 170 | img.width = scale * originalSize.width; 171 | img.height = scale * originalSize.height; 172 | iplImage.canvas = document.getElementById(canvasId); 173 | iplImage.canvas.width = img.width; 174 | iplImage.canvas.height = img.height; 175 | iplImage.canvas.getContext("2d").drawImage(img, 0, 0); 176 | iplImage.width = iplImage.canvas.width; 177 | iplImage.height = iplImage.canvas.height; 178 | iplImage.RGBA = new Array(iplImage.width * iplImage.width * CHANNELS); 179 | iplImage.imageData = iplImage.canvas.getContext("2d").getImageData(0, 0, iplImage.canvas.width, iplImage.canvas.height); 180 | cvImageData2RGBA(iplImage); 181 | cvShowImageToCanvas(canvasId, iplImage); 182 | event = null; 183 | }; 184 | reader.onerror = function(event){ 185 | if (event.target.error.code == event.target.error.NOT_READABLE_ERR) { 186 | alert(ERROR.NOT_READ_FILE); 187 | } 188 | }; 189 | } 190 | catch(ex){ 191 | alert("cvLoadImageToCanvasAtEventFile : " + ex); 192 | } 193 | } 194 | 195 | //IplImage型のRGBAの値をimageDataへ転送 196 | //cvShowImageで呼び出されることを想定 197 | //入力 198 | //iplImage IplImage型 自身のimageDataへ自身のRGBAの値がコピーされる画像 199 | //出力 200 | //なし 201 | function cvRGBA2ImageData(iplImage){ 202 | try{ 203 | if(cvUndefinedOrNull(iplImage)) throw "iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 204 | for(var i = 0 ; i < iplImage.height ; i++){ 205 | var is = i * iplImage.width * CHANNELS; 206 | var js = 0; 207 | for(var j = 0 ; j < iplImage.width ; j++){ 208 | for(var c = 0 ; c < CHANNELS; c++){ 209 | iplImage.imageData.data[c + js + is] = iplImage.RGBA[c + js + is]; 210 | } 211 | js += CHANNELS; 212 | } 213 | } 214 | } 215 | catch(ex){ 216 | alert("RGBA2ImageData : " + ex); 217 | } 218 | } 219 | //IplImage型のimageDataの値をRGBAへ転送 220 | //cvLoad**で呼び出されることを想定 221 | //入力 222 | //iplImage IplImage型 自身のRGBAへ自身のimageDataの値がコピーされる画像 223 | //出力 224 | //なし 225 | function cvImageData2RGBA(iplImage){ 226 | try{ 227 | if(cvUndefinedOrNull(iplImage)) throw "iplImage" + ERROR.IS_UNDEFINED_OR_NULL; 228 | for(var i = 0 ; i < iplImage.height ; i++){ 229 | var is = i * iplImage.width * CHANNELS; 230 | var js = 0; 231 | for(var j = 0 ; j < iplImage.width ; j++){ 232 | for(var c = 0 ; c < CHANNELS; c++){ 233 | iplImage.RGBA[c + js + is] = iplImage.imageData.data[c + js + is] ; 234 | } 235 | js += CHANNELS; 236 | } 237 | } 238 | } 239 | catch(ex){ 240 | alert("RGBA2ImageData : " + ex); 241 | } 242 | } 243 | 244 | //canvasタグからIplImageへ転送 245 | //入力 246 | //canvasId canvasタグ canvasタグのオブジェクト 247 | //出力 248 | //IplImage型 249 | function cvGetIplImageAtCanvas(canvasId){ 250 | var iplImage = null; 251 | try{ 252 | var canvasElement = document.getElementById(canvasId); 253 | iplImage = cvGetIplImageAtCanvasElement(canvasElement); 254 | } 255 | catch(ex){ 256 | alert("cvGetIplImageAtCanvas : " + ex); 257 | } 258 | return iplImage; 259 | } 260 | 261 | //canvasエレメントからIplImageへ転送 262 | //入力 263 | //canvasElement canvasエレメント canvasのオブジェクト 264 | //出力 265 | //IplImage型 266 | function cvGetIplImageAtCanvasElement(canvasElement){ 267 | var iplImage = null; 268 | try{ 269 | if(cvUndefinedOrNull(canvasElement)) 270 | throw "canvas" + ERROR.IS_UNDEFINED_OR_NULL; 271 | 272 | iplImage = cvCreateImage(canvasElement.width, canvasElement.height); 273 | iplImage.imageData = 274 | canvasElement.getContext("2d").getImageData(0, 0, canvasElement.width, canvasElement.height); 275 | cvImageData2RGBA(iplImage); 276 | } 277 | catch(ex){ 278 | alert("cvGetIplImageAtCanvasElement : " + ex); 279 | } 280 | return iplImage; 281 | } 282 | 283 | //imgタグのsrcからiplImageに変換する 284 | //入力 285 | //imgId Id型 変換されるimgタグ 286 | //出力 287 | //iplImage型 288 | //備考 289 | //ローカル環境では動かない 290 | function cvGetIplImageAtImg(imgId){ 291 | var iplImage = null; 292 | try{ 293 | if(cvUndefinedOrNull(imgId)) throw "imgId" + ERROR.IS_UNDEFINED_OR_NULL; 294 | var imgElement = document.getElementById(imgId); 295 | iplImage = new IplImage(); 296 | iplImage.canvas = cvGetCanvasAtImgElement(imgElement); 297 | iplImage.width = iplImage.canvas.width; 298 | iplImage.height = iplImage.canvas.height; 299 | iplImage.RGBA = new Array(iplImage.width * iplImage.width * CHANNELS); 300 | var context = iplImage.canvas.getContext("2d"); 301 | iplImage.imageData = context.getImageData(0, 0, iplImage.canvas.width, iplImage.canvas.height); 302 | for(var i = 0 ; i < iplImage.height ; i++){ 303 | var is = i * iplImage.width * CHANNELS; 304 | var js = 0; 305 | for(var j = 0 ; j < iplImage.width ; j++){ 306 | for(var c = 0 ; c < CHANNELS ; c++){ 307 | iplImage.RGBA[c + js + is] = iplImage.imageData.data[c + js + is]; 308 | } 309 | js += CHANNELS; 310 | } 311 | } 312 | } 313 | catch(ex){ 314 | alert("cvGetIplImageAtImg : " + ex); 315 | } 316 | 317 | return iplImage; 318 | } 319 | 320 | 321 | //imgタグからcanvasへ転送 322 | //cvLoadImageで呼び出されることを想定 323 | //入力 324 | //image imgタグ imgタグのオブジェクト 325 | //出力 326 | //canvasタグ 327 | function cvGetCanvasAtImgElement(image){ 328 | var canvas = null; 329 | try{ 330 | if(cvUndefinedOrNull(image)) throw "image" + ERROR.IS_UNDEFINED_OR_NULL; 331 | 332 | canvas = document.createElement('canvas'); 333 | 334 | if(cvUndefinedOrNull(canvas)) throw "canvas" + ERROR.IS_UNDEFINED_OR_NULL; 335 | 336 | canvas.width = image.width; 337 | canvas.height = image.height; 338 | 339 | canvas.getContext("2d").drawImage(image, 0, 0, canvas.width, canvas.height); 340 | } 341 | catch(ex){ 342 | alert("cvGetCanvasAtImgElement : " + ex); 343 | } 344 | return canvas; 345 | } 346 | 347 | // get Image true size 348 | function cvGetOriginalSizeAtImgElement(image){ 349 | var w = 0 , h = 0 ; 350 | try{ 351 | if(cvUndefinedOrNull(image)) throw "image" + ERROR.IS_UNDEFINED_OR_NULL; 352 | 353 | w = image.width ; 354 | h = image.height ; 355 | 356 | if ( image.naturalWidth !== undefined ) { // for Firefox, Safari, Chrome 357 | w = image.naturalWidth; 358 | h = image.naturalHeight; 359 | 360 | } else if ( image.runtimeStyle !== undefined ) { // for IE 361 | var run = image.runtimeStyle; 362 | var mem = { w: run.width, h: run.height }; // keep runtimeStyle 363 | run.width = "auto"; 364 | run.height = "auto"; 365 | w = image.width; 366 | h = image.height; 367 | run.width = mem.w; 368 | run.height = mem.h; 369 | 370 | } else { // for Opera 371 | var mem = { w: image.width, h: image.height }; // keep original style 372 | image.removeAttribute("width"); 373 | image.removeAttribute("height"); 374 | w = image.width; 375 | h = image.height; 376 | image.width = mem.w; 377 | image.height = mem.h; 378 | } 379 | } 380 | catch(ex){ 381 | alert("cvGetOriginalSizeAtImgElement : " + ex); 382 | } 383 | 384 | return {width:w, height:h}; 385 | } -------------------------------------------------------------------------------- /module/ml.js: -------------------------------------------------------------------------------- 1 | //////////////メモ///////////////////////// 2 | // 3 | // svmはC-SVMのSMOのみ利用可能 4 | // opencv.jsが必要 5 | // 6 | /////////////////////////////////////////// 7 | 8 | 9 | //------------------データ型------------------------ 10 | //SVMの学習パラメータ 11 | var CvSVMParams = function(){ 12 | svm_type: 0; //未使用 13 | kernel_type: 0; //CV_SVM_KERNEL_TYPE型 14 | degree: 1; // CV_SVM_KERNEL_TYPE.POLY 用 15 | gamma: 1; // CV_SVM_KERNEL_TYPE.POLY/CV_SVM_KERNEL_TYPE.RBF/CV_SVM_KERNEL_TYPE.SIGMOID 用 16 | coef0: 0; // CV_SVM_KERNEL_TYPE.POLY/CV_SVM_KERNEL_TYPE.SIGMOID 用 17 | 18 | C: 0; //C-SVMのC 19 | nu: 0; // 未使用 20 | p: 0; // 未使用 21 | term_crit: null; // 終了条件 22 | tolerance: 0; // ラグランジュ乗数評価時の余裕値 23 | minLearnData: 0; //学習データの最低個数 24 | } 25 | 26 | //SVMクラス 27 | var CvSVM = function(){ 28 | this.class_weights = null; // 学習した重み 29 | this.b = 0; //バイアス初期化 30 | 31 | this.svmP = null; 32 | this.svmIndexes = null; //サポートベクターになるindex 33 | 34 | //-------Trainメソッドの引数trainss変数で初期化される---------- 35 | //学習データ 36 | this.transs = null; 37 | // ラグランジュの未定乗数 38 | this.lambda = null; 39 | // ラグランジュ係数の値を保存するキャッシュ 40 | this.eCache = null; 41 | 42 | } 43 | 44 | //2層パーセプトロンの学習パラメータ 45 | var CvPerceptronParams = function(){ 46 | nu: 1; //学習効率 47 | term_crit: null; // 終了条件 48 | } 49 | 50 | //2層パーセプトロンクラス 51 | var CvPerceptron = function(){ 52 | this.class_weights = null; //学習した重み 53 | this.bias = 0; //バイアス 54 | this.pctP = null; 55 | } 56 | 57 | 58 | //------------------定数------------------------ 59 | //SVMのカーネルタイプ 60 | var CV_SVM_KERNEL_TYPE = { 61 | LINEAR: 0, //マッピングは行われない 62 | POLY: 1, //多項式カーネル 63 | RBF: 2, //動径基底関数カーネル 64 | SIGMOID: 3 //シグモイド関数カーネル 65 | } 66 | 67 | //------------------メソッド------------------------ 68 | 69 | CvSVM.prototype._save = function(fileNameFullPath){ 70 | try{ 71 | } 72 | catch(ex){ 73 | alert("CvSVM.prototype._save : " + ex); 74 | } 75 | } 76 | 77 | CvSVM.prototype._kernel = function(trains2, trains1){ 78 | var r = 0.0; 79 | try{ 80 | switch(this.svmP.kernel_type){ 81 | case CV_SVM_KERNEL_TYPE.POLY: // 多項式カーネル 82 | var p = this.svmP.degree; // Tuning Parameter 83 | r = this.svmP.coef0; // Tuning Parameter 84 | var g = this.svmP.gamma; // Tuning Parameter 85 | for(var i = 0; i < trains2.length; i++ ) 86 | r += g * trains2[i] * trains1[i]; 87 | r = Math.pow( r, p ); 88 | break; 89 | case CV_SVM_KERNEL_TYPE.RBF: // ガウシアン(動径基底関数?)カーネル 90 | var g = this.svmP.gamma; // Tuning Parameter 91 | for( var i = 0; i < trains2.length; i++ ) 92 | r += (trains2[i] - trains1[i]) * (trains2[i] - trains1[i]); 93 | r = Math.exp(-r / (2*g*g)); 94 | break; 95 | default: //CV_SVM_KERNEL_TYPE.LINEAR 96 | for(var i = 0; i < trains2.length; i++ ) 97 | r += trains2[i] * trains1[i]; 98 | break; 99 | } 100 | } 101 | catch(ex){ 102 | alert("CvSVM.prototype._kernel : " + ex); 103 | } 104 | return r; 105 | } 106 | 107 | CvSVM.prototype._f = function(idx1, trainss, responses){ 108 | var F = 0.0; 109 | try{ 110 | for(var idx2 = 0; idx2 < trainss.length; idx2++ ){ 111 | if( this.lambda[idx2] == 0.0 ) continue; 112 | F += this.lambda[idx2] * responses[idx2] * this._kernel(trainss[idx2], trainss[idx1]); 113 | } 114 | F -= this.b; 115 | } 116 | catch(ex){ 117 | alert("CvSVM.prototype._f : " + ex); 118 | } 119 | return F; 120 | } 121 | 122 | //SMOメソッド 123 | CvSVM.prototype._stepSMO = function(idx1, idx2, e1, trainss, responses){ 124 | try{ 125 | if(idx1 == idx2) return 0; 126 | var lambda1Old = this.lambda[idx1], lambda1New; 127 | var lambda2Old = this.lambda[idx2], lambda2New; 128 | var U, V, e2; 129 | if( responses[idx1] != responses[idx2] ){ 130 | U = Math.max(0.0, lambda1Old - lambda2Old); 131 | V = Math.min(this.svmP.C, this.svmP.C+lambda1Old - lambda2Old); 132 | } 133 | else{ 134 | U = Math.max(0.0, lambda1Old + lambda2Old - this.svmP.C); 135 | V = Math.min(this.svmP.C, lambda1Old + lambda2Old); 136 | } 137 | if( U == V ) return 0; 138 | 139 | var k11 = this._kernel(trainss[idx1], trainss[idx1]); 140 | var k22 = this._kernel(trainss[idx1], trainss[idx2]); 141 | var k12 = this._kernel(trainss[idx1], trainss[idx2]); 142 | var k = k11 + k22 - 2.0*k12; 143 | if( this.lambda[idx2] > this.svmP.term_crit.epsilon && this.lambda[idx2] < (this.svmP.C - this.svmP.term_crit.epsilon) ) 144 | e2 = this.eCache[idx2]; 145 | else 146 | e2 = this._f(idx2, trainss, responses) - responses[idx2]; 147 | 148 | var bClip = false; 149 | if( k <= 0.0 ){ 150 | // this.lambda[idx1] = U のときの目的関数の値 151 | lambda1New = U; 152 | lambda2New = lambda2Old + responses[idx1] * responses[idx2] * (lambda1Old - lambda1New); 153 | this.lambda[idx1] = lambda1New; // 仮置き 154 | this.lambda[idx2] = lambda2New; 155 | var v1 = this._f(idx2, trainss, responses) + this.b - responses[idx2] * lambda2Old * k22 - responses[idx1] * lambda1Old * k12; 156 | var v2 = this._f(idx1, trainss, responses) + this.b - responses[idx2] * lambda2Old * k12 - responses[idx1] * lambda1Old * k11; 157 | var Lobj = lambda2New + lambda1New - k22 * lambda2New * lambda2New / 2.0 - k11 * lambda1New * lambda1New / 2.0 158 | - responses[idx2] * responses[idx1] * k12 * lambda2New * lambda1New 159 | - responses[idx2] * lambda2New * v1 - responses[idx1] * lambda1New * v2; 160 | 161 | // this.lambda[idx1] = V のときの目的関数の値 162 | lambda1New = V; 163 | lambda2New = lambda2Old + responses[idx1] * responses[idx2] * (lambda1Old - lambda1New); 164 | this.lambda[idx1] = lambda1New; // 仮置き 165 | this.lambda[idx2] = lambda2New; 166 | v1 = this._f(idx2, trainss, responses) + this.b - responses[idx2] * lambda2Old * k22 - responses[idx1] * lambda1Old * k12; 167 | v2 = this._f(idx1, trainss, responses) + this.b - responses[idx2] * lambda2Old * k12 - responses[idx1] * lambda1Old * k11; 168 | var Hobj = lambda2New + lambda1New - k22 * lambda2New * lambda2New / 2.0 - k11 * lambda1New * lambda1New / 2.0 169 | - responses[idx2] * responses[idx1] * k12 * lambda2New * lambda1New 170 | - responses[idx2] * lambda2New * v1 - responses[idx1] * lambda1New * v2; 171 | 172 | if( Lobj > Hobj + this.svmP.term_crit.epsilon ){ 173 | bClip = true; 174 | lambda1New = U; 175 | } 176 | else if( Lobj < Hobj - this.svmP.term_crit.epsilon ){ 177 | bClip = true; 178 | lambda1New = V; 179 | } 180 | else{ 181 | bClip = true; 182 | lambda1New = lambda1Old; 183 | } 184 | this.lambda[idx1] = lambda1Old; // 元に戻す 185 | this.lambda[idx2] = lambda2Old; 186 | } 187 | else{ 188 | lambda1New = lambda1Old + (responses[idx1] * (e2-e1) / k); 189 | if( lambda1New > V ){ 190 | bClip = true; 191 | lambda1New = V; 192 | } 193 | else if( lambda1New < U ){ 194 | bClip = true; 195 | lambda1New = U; 196 | } 197 | } 198 | 199 | // if(lambda1New > 100) console.log("lambda1New =" + lambda1New + " : lambda1Old = " + lambda1Old); 200 | // console.log("Math.abs(lambda1New - lambda1Old) = " + Math.abs(lambda1New - lambda1Old)); 201 | // console.log("this.svmP.term_crit.epsilon * (lambda1New+lambda1Old+this.svmP.term_crit.epsilon) = " + 202 | // (this.svmP.term_crit.epsilon * (lambda1New+lambda1Old+this.svmP.term_crit.epsilon)) ); 203 | 204 | if( Math.abs(lambda1New - lambda1Old) < this.svmP.term_crit.epsilon * (lambda1New + lambda1Old + this.svmP.term_crit.epsilon) ) 205 | return 0; 206 | 207 | // this.lambda[idx2]更新 208 | lambda2New = lambda2Old + responses[idx1] * responses[idx2] * (lambda1Old - lambda1New); 209 | // b更新 210 | var old_b = this.b; 211 | if( this.lambda[idx1] > this.svmP.term_crit.epsilon && this.lambda[idx1] < (this.svmP.C-this.svmP.term_crit.epsilon) ) 212 | this.b += e1 + (lambda1New - lambda1Old) * responses[idx1] * k11 + (lambda2New - lambda2Old) * responses[idx2] * k12; 213 | else if( this.lambda[idx2] > this.svmP.term_crit.epsilon && this.lambda[idx2] < (this.svmP.C-this.svmP.term_crit.epsilon) ) 214 | this.b += e2 + (lambda1New - lambda1Old) * responses[idx1] * k12 + (lambda2New - lambda2Old) * responses[idx2] * k22; 215 | else 216 | this.b += (e1 + (lambda1New - lambda1Old) * responses[idx1] * k11 + 217 | (lambda2New - lambda2Old) * responses[idx2] * k12 + e2 + (lambda1New - lambda1Old) * responses[idx1] * k12 + 218 | (lambda2New - lambda2Old) * responses[idx2] * k22 ) / 2.0; 219 | 220 | // err更新 221 | for( var m = 0; m < trainss.length; m++ ){ 222 | if( m == idx1 || m == idx2 ) continue; 223 | else if( this.lambda[m] > this.svmP.term_crit.epsilon && this.lambda[m] < (this.svmP.C-this.svmP.term_crit.epsilon) ) 224 | this.eCache[m] = this.eCache[m] + responses[idx2] * (lambda2New - lambda2Old) * this._kernel( trainss[idx2], trainss[m] ) 225 | + responses[idx1] * (lambda1New - lambda1Old) * this._kernel( trainss[idx1], trainss[m] ) + old_b - this.b; 226 | } 227 | 228 | this.lambda[idx1] = lambda1New; 229 | this.lambda[idx2] = lambda2New; 230 | if( bClip ){ 231 | if( lambda1New > this.svmP.term_crit.epsilon && lambda1New < (this.svmP.C-this.svmP.term_crit.epsilon) ) 232 | this.eCache[idx1] = this._f(idx1, trainss, responses) - responses[idx1]; 233 | } 234 | else this.eCache[idx1] = 0.0; 235 | 236 | this.eCache[idx2] = this._f(idx2, trainss, responses) - responses[idx2]; 237 | } 238 | catch(ex){ 239 | alert("CvSVM.prototype._stepSMO : " + ex); 240 | } 241 | 242 | return 1; 243 | } 244 | 245 | //引数からふたつめの更新データを探索し_stepSMOメソッドで更新 246 | CvSVM.prototype._update = function(idx1, e1, trainss, responses){ 247 | try{ 248 | var maxE2 = 0.0; 249 | var e2; 250 | var maxE2Idx = -1; 251 | var offset; 252 | //探索条件1 253 | offset = parseInt(Math.random() * trainss.length); 254 | for(var idx2 = 0 ; idx2 < trainss.length ; idx2++){ 255 | var pos = (idx2 + offset) % trainss.length; 256 | if(this.lambda[pos] > this.svmP.term_crit.epsilon && this.lambda[pos] < (this.svmP.C - this.svmP.term_crit.epsilon)){ 257 | e2 = this.eCache[pos]; 258 | var dmy = Math.abs(e2 - e1); 259 | if(dmy > maxE2){ 260 | maxE2 = dmy; 261 | maxE2Idx = pos; 262 | } 263 | } 264 | } 265 | if(maxE2Idx >= 0 && this._stepSMO(idx1, maxE2Idx, e1, trainss, responses) == 1) 266 | return 1; 267 | 268 | //探索条件2 269 | offset = parseInt(Math.random() * trainss.length); 270 | for(var idx2 = 0 ; idx2 < trainss.length ; idx2++){ 271 | var pos = (idx2 + offset) % trainss.length; 272 | if(this.lambda[pos] > this.svmP.term_crit.epsilon && this.lambda[pos] < (this.svmP.C - this.svmP.term_crit.epsilon) && 273 | this._stepSMO(idx1, idx2, e1, trainss, responses) == 1) 274 | return 1; 275 | } 276 | 277 | //探索条件3 278 | offset = parseInt(Math.random() * trainss.length); 279 | for(var idx2 = 0 ; idx2 < trainss.length ; idx2++){ 280 | var pos = (idx2 + offset) % trainss.length; 281 | if( ! (this.lambda[pos] > this.svmP.term_crit.epsilon && this.lambda[pos] < (this.svmP.C - this.svmP.term_crit.epsilon)) && 282 | this._stepSMO(idx1, idx2, e1, trainss, responses) == 1) 283 | return 1; 284 | } 285 | } 286 | catch(ex){ 287 | alert("CvSVM.prototype._update : " + ex); 288 | } 289 | 290 | return 0; 291 | } 292 | 293 | //ひとつめの引数の選択するか検証 294 | CvSVM.prototype._examinUpdate = function(idx1, trainss, responses){ 295 | try{ 296 | var yF1; 297 | var e1; 298 | var response = responses[idx1]; 299 | if(this.lambda[idx1] > this.svmP.term_crit.epsilon && this.lambda[idx1] < (this.svmP.C - this.svmP.term_crit.epsilon)) 300 | e1 = this.eCache[idx1]; 301 | else e1 = this._f(idx1, trainss, responses) - response; 302 | 303 | yF1 = e1 * response; 304 | 305 | //KKT条件のチェック 306 | if( (this.lambda[idx1] < (this.svmP.C - this.svmP.term_crit.epsilon) && yF1 < -this.svmP.tolerance) || 307 | (this.lambda[idx1] > this.svmP.term_crit.epsilon && yF1 > this.svmP.torelance) ) 308 | return this._update(idx1, e1, trainss, responses); 309 | } 310 | catch(ex){ 311 | alert("CvSVM.prototype._examinUpdate : " + ex); 312 | } 313 | return 0; 314 | } 315 | 316 | 317 | 318 | //2層サポートベクターマシンによる学習 319 | //入力 320 | // inputss 二次元array 学習データの二次元配列.inputss[学習ナンバー][次元] 321 | // answers array inputssの正解値配列(1 or -1) answers[学習ナンバー] 322 | // nyu 少数型 学習倍率 低くするとと正確だが収束が遅い 323 | // termcriteria CvTermCriteria型 type以外の値を指定する 324 | //出力 325 | //CvPerceptromParams型 326 | CvSVM.prototype.train = function(trainss, responses, varIndex, sampleIndex, cvSVMParams) { 327 | try{ 328 | if(cvUndefinedOrNull(cvSVMParams)) 329 | throw "cvSVMParams" + ERROR.IS_UNDEFINED_OR_NULL; 330 | if(cvUndefinedOrNull(trainss) || trainss.length < cvSVMParams.minLearnData || 331 | cvUndefinedOrNull(responses) || responses.length < cvSVMParams.minLearnData) 332 | throw "trainssかresponses、もしくはその両方がundefinedかnull、または学習データの数が足りていません
" + 333 | cvSVMParams.minLearnData + "個以上の学習データを読み込ませて下さい"; 334 | else if(trainss.length != responses.length) 335 | throw "trainss.length != responses.lengthです
" + 336 | "データ長を等しくして下さい"; 337 | 338 | /////////////////変数の初期化/////////////////////// 339 | //学習データのコピー 340 | this.trainss = new Array(trainss.length); 341 | for(var i = 0 ; i < this.trainss.length ; i++){ 342 | this.trainss[i] = new Array(trainss[i].length); 343 | for(var j = 0 ; j < this.trainss[i].length ; j++){ 344 | this.trainss[i][j] = trainss[i][j]; 345 | } 346 | } 347 | 348 | // ラグランジュの未定乗数 349 | this.lambda = new Array(trainss.length); 350 | for(var i = 0; i < this.lambda.length; this.lambda[i++] = 0); 351 | // ラグランジュ係数の値を保存するキャッシュ 352 | this.eCache = new Array(this.trainss.length); 353 | //重み 354 | this.class_weights = new Array(trainss.length); 355 | for(var i = 0; i < this.class_weights.length; this.class_weights[i++] = 0); 356 | 357 | this.svmP = cvSVMParams; 358 | 359 | this.svmIndexes = new Array(); 360 | 361 | ///////////////////////////////////////////////////////////// 362 | 363 | var alldata = true;//すべてのデータを処理する場合 364 | var changed;//変更があった 365 | 366 | // ループ変数 367 | var loop = 0; 368 | while(loop < this.svmP.term_crit.max_iter){ 369 | changed = 0; 370 | for(var i = 0 ; i < trainss.length; i++){ 371 | if( alldata || (this.lambda[i] > this.svmP.term_crit.epsilon && this.lambda[i] < (this.svmP.C-this.svmP.term_crit.epsilon)) ) 372 | changed += this._examinUpdate(i, trainss, responses); 373 | } 374 | if( alldata ){ 375 | alldata = false; 376 | if(changed == 0) break; 377 | } 378 | else if(changed == 0) alldata = false; 379 | loop++; 380 | if(changed != 0) console.log("loop = " + loop + " : changed = " + changed); 381 | } 382 | for( var i = 0; i < trainss.length; i++ ){ 383 | if( this.lambda[i] != 0.0 ) this.svmIndexes.push(i); 384 | } 385 | 386 | //重み計算 387 | for(var i = 0; i < this.svmIndexes.length ; i++) { 388 | var svmIdx = this.svmIndexes[i]; 389 | this.class_weights[svmIdx] = responses[svmIdx] * this.lambda[svmIdx]; 390 | } 391 | } 392 | catch(ex){ 393 | alert("CvSVM.prototype.Train : " + ex); 394 | } 395 | return 1; 396 | } 397 | 398 | //2層パーセプトロンによる予測 399 | //入力 400 | //predicts array 予測データ 401 | //trains 2次元array 重みの学習に使った学習データ 402 | //出力 403 | //1 or -1 404 | CvSVM.prototype.predict = function(predicts){ 405 | var ans = 0.0; 406 | try{ 407 | if(cvUndefinedOrNull(predicts)) 408 | throw "predicts" + ERROR.IS_UNDEFINED_OR_NULL; 409 | 410 | for(var i = 0; i < this.svmIndexes.length; i++ ){ 411 | var idx = this.svmIndexes[i]; 412 | ans += this.class_weights[idx] * this._kernel(this.trainss[idx], predicts); 413 | } 414 | ans -= this.b; 415 | 416 | ans = ans > 0.0 ? 1 : -1; 417 | } 418 | catch(ex){ 419 | alert("CvSVM.prototype.Predict : " + ex); 420 | } 421 | 422 | return ans; 423 | } 424 | 425 | CvSVM.prototype.get_support_vector = function(idx){ 426 | try{ 427 | if(this.class_weights.length < idx || idx < 0) 428 | throw "idxが境界外です"; 429 | 430 | return this.class_weights[this.svmIndexes[idx]]; 431 | } 432 | catch(ex){ 433 | alert("CvSVM.prototype.get_support_vector : " +ex); 434 | } 435 | } 436 | 437 | CvSVM.prototype.get_support_vector_count = function(){ 438 | return this.class_weights.length; 439 | } 440 | 441 | CvSVM.prototype.get_support_vector_index = function(){ 442 | return this.svmIndexes; 443 | } 444 | 445 | //2層パーセプトロンによる学習 446 | //入力 447 | // inputss 二次元array 学習データの二次元配列.inputss[学習ナンバー][次元] 448 | // answers array inputssの正解値配列(1 or -1) answers[学習ナンバー] 449 | // cvPerceptronParams CvPerceptronParam型 450 | //出力 451 | //なし 452 | CvPerceptron.prototype.train = function(trainss, responses, cvPerceptronParams){ 453 | try{ 454 | if(cvUndefinedOrNull(trainss) || cvUndefinedOrNull(responses) || 455 | cvUndefinedOrNull(cvPerceptronParams)) 456 | throw "引数のどれか" + ERROR.IS_UNDEFINED_OR_NULL; 457 | 458 | this.class_weights = new Array(trainss[0].length); 459 | for(var i = 0 ; i < this.class_weights.length ; i++) this.class_weights[i] = 0; 460 | this.bias = 0; 461 | 462 | this.pctP = cvPerceptronParams; 463 | 464 | var max = -1; 465 | for(var i = 0 ; i < trainss.length; i++){ 466 | var dmy = 0; 467 | for(var j = 0 ; j < trainss[i].length ; j++) 468 | dmy += trainss[i][j] * trainss[i][j]; 469 | if(max < dmy) max = dmy; 470 | } 471 | max = Math.sqrt(max); 472 | 473 | var nowLoop = 0; 474 | while(true){ 475 | var isMiss = false; 476 | for(var i = 0 ; i < responses.length; i++){ 477 | var sum = 0; 478 | for(var j = 0 ; j < trainss[i].length ; j++) 479 | sum += this.class_weights[j] * trainss[i][j]; 480 | if(responses[i] *(sum + this.bias) <= this.pctP.term_crit.epsilon){ 481 | isMiss = true; 482 | var na = this.pctP.nu * responses[i]; 483 | for(var j = 0 ; j < trainss[i].length; j++) 484 | this.class_weights[j] += na * trainss[i][j]; 485 | this.bias += na * max * max; 486 | } 487 | } 488 | nowLoop++; 489 | if(this.pctP.term_crit.max_iter < nowLoop) break; 490 | else if(! isMiss) break; 491 | } 492 | } 493 | catch(ex){ 494 | alert("cvPerceptron.prototype.Train : " + ex); 495 | } 496 | 497 | return 1; 498 | } 499 | 500 | 501 | //2層パーセプトロンによる予測 502 | //入力 503 | //inputs array 予測データ 504 | //出力 505 | //1 or -1 506 | CvPerceptron.prototype.predict = function(inputs){ 507 | var ans = 0; 508 | try{ 509 | if(cvUndefinedOrNull(inputs)) 510 | throw "inputs" + ERROR.IS_UNDEFINED_OR_NULL; 511 | 512 | var sum = 0; 513 | for(var i = 0 ; i < inputs.length ; i++) 514 | sum += this.class_weights[i] * inputs[i]; 515 | sum += this.bias; 516 | 517 | ans = (sum >= 0) ? 1 : -1; 518 | } 519 | catch(ex){ 520 | alert("cvPerceptron.prototype.Predict : " + ex); 521 | } 522 | return ans; 523 | } 524 | 525 | -------------------------------------------------------------------------------- /module/test.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | //cvmK-SVDのテスト 4 | //入力 5 | //signals cvMat型 ひとつの観測信号を縦ベクトルとして並べた行列 6 | //dic cvMat型 更新前の辞書 7 | //coess cvMat型 係数の縦ベクトルを並べた行列 dic.cols == coess.rows 8 | //cvTermCriteriaCoessZero CvTermCriteria型 epsの値が基底ベクトルの値を0とする閾値 9 | //cvTermCriteriaDiff CvTermCriteria型 epsの値が復元信号と原信号の差の絶対値の総和の閾値 10 | //出力 11 | //bool型 問題なければtrue 12 | function test_cvmK_SVD(signals, dic, coess, cvTermCriteria, cvTermCriteriaDiff, test_cvTermCriteria){ 13 | var rtn = true; 14 | try{ 15 | var ups = cvmK_SVD(signals, dic, coess, cvTermCriteria, cvTermCriteriaDiff); 16 | 17 | var upDic = ups[0]; 18 | var upCoess = ups[1]; 19 | 20 | cvDWriteMatrix(upDic, "更新した辞書"); 21 | cvDWriteMatrix(upCoess, "更新した係数"); 22 | } 23 | catch(ex){ 24 | alert("test_cvmK_SVD : " + ex); 25 | } 26 | return rtn; 27 | } 28 | 29 | 30 | //cvmOMPのテスト 31 | //入力 32 | //mat CvMat型 係数を求める行列 33 | //dic CvMat型 辞書行列 dic.rows = dic.cols = mat.rows * mat.cols 34 | //isDraw bool型 計算途中の配列を描画するか 35 | //cvTermCriteria CvTermCriteria型 計算精度 36 | //eigenCriteria CvTermCriteria型 内部の固有値計算の精度 37 | //test_cvTermCriteria CvTermCriteria型 最終的に計算が合っているか確認する精度 38 | //出力 39 | //bool型 問題なければtrue 40 | function test_cvmOMP(mat, dic, isDraw, 41 | cvTermCriteria, eigenTermCriteria, test_cvTermCriteria){ 42 | var rtn = true; 43 | try{ 44 | //matを1列の縦ベクトルに変換 45 | var vec = cvCreateMat(mat.rows * mat.cols, 1); 46 | for(var i = 0 ; i < vec.rows ; i++){ 47 | vec.vals[i] = mat.vals[i]; 48 | } 49 | 50 | var omp = cvmOMP(vec, dic, cvTermCriteria, eigenTermCriteria); 51 | 52 | var recon = cvmMul(dic, omp); 53 | 54 | var subv = cvmSub(vec, recon); 55 | 56 | if(isDraw){ 57 | cvDWriteMatrix(dic, "辞書行列"); 58 | cvDWriteMatrix(cvmTranspose(omp), "係数ベクトル"); 59 | cvDWriteMatrix(cvmTranspose(recon), "再構成ベクトル"); 60 | cvDWriteMatrix(cvmTranspose(vec), "オリジナルベクトル"); 61 | cvDWriteMatrix(cvmTranspose(subv), "差分ベクトル"); 62 | } 63 | 64 | for(var i = 0 ; i < subv.rows ; i++){ 65 | if(Math.abs(subv.vals[i]) > test_cvTermCriteria.eps){ 66 | rtn = false; 67 | break; 68 | } 69 | } 70 | } 71 | catch(ex){ 72 | alert("test_cvmOMP : " + ex); 73 | } 74 | return rtn; 75 | } 76 | 77 | //直交性のテスト 78 | //入力 79 | //mat CvMat型 調べる行列 80 | //isDraw bool型 計算途中の配列を描画するか 81 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 82 | //出力 83 | //bool型 問題なければtrue 84 | function test_cvmOrthogonalMatrix(mat, isDraw, test_cvTermCriteria){ 85 | var rtn = false; 86 | try{ 87 | var mattr = cvmTranspose(mat); 88 | var mm1 = cvmMul(mat, mattr); 89 | var mm2 = cvmMul(mattr, mat); 90 | 91 | if(isDraw) cvDWriteMatrix(mm1, "mat * mat^tr"); 92 | if(isDraw) cvDWriteMatrix(mm2, "mat^tr * mat"); 93 | 94 | for(var i = 0 ; i < mm1.rows ; i++){ 95 | for(var j = 0 ; j < mm1.cols ; j++){ 96 | if(Math.abs(mm1.vals[j + i * mm1.cols] - (i == j ? 1 : 0)) > test_cvTermCriteria.eps){ 97 | throw "mat * mat^trが直交ではありません"; 98 | } 99 | } 100 | } 101 | for(var i = 0 ; i < mm2.rows ; i++){ 102 | for(var j = 0 ; j < mm2.cols ; j++){ 103 | if(Math.abs(mm2.vals[j + i * mm2.cols] - (i == j ? 1 : 0)) > test_cvTermCriteria.eps){ 104 | throw "mat^tr * matが直交ではありません"; 105 | } 106 | } 107 | } 108 | 109 | rtn = true; 110 | } 111 | catch(ex){ 112 | alert("test_cvmOrthogonalMatrix : " + ex); 113 | } 114 | return rtn; 115 | } 116 | 117 | 118 | //cvmSVDの結果をテスト 119 | //入力 120 | //mat CvMat型 調べる行列 121 | //isDraw bool型 計算途中の配列を描画するか 122 | //cvTermCriteria CvTermCriteria型 計算精度 123 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 124 | //出力 125 | //bool型 問題なければtrue 126 | function test_cvmSVD(mat, isDraw, cvTermCriteria, test_cvTermCriteria){ 127 | 128 | var rtn = false; 129 | try{ 130 | //バリデーション 131 | if(cvUndefinedOrNull(cvTermCriteria)) 132 | cvTermCriteria = new CvTermCriteria(); 133 | 134 | if(cvUndefinedOrNull(test_cvTermCriteria)) 135 | test_cvTermCriteria = new CvTermCriteria(); 136 | 137 | var WLR = cvmSVD(mat, cvTermCriteria); 138 | if(!WLR) throw "cvmSVDが求まりませんでした"; 139 | 140 | var W = WLR[0]; 141 | var L = WLR[1]; 142 | var R = WLR[2]; 143 | 144 | //L,Rがユニタリー行列か 145 | //L,Rの縦横サイズのチェック 146 | if(cvUndefinedOrNull(L) || L.rows != L.cols){ 147 | if(isDraw)cvDWriteMatrix(L, "L"); 148 | throw "Lが正方行列ではありません"; 149 | } 150 | if(cvUndefinedOrNull(R) || R.rows != R.cols) 151 | throw "Rが正方行列ではありません"; 152 | 153 | if(isDraw) document.write("Lの大きさチェック
"); 154 | 155 | //列ベクトルの大きさチェック 156 | for(var j = 0 ; j < L.cols ; j++){ 157 | var norm = 0; 158 | for(var i = 0 ; i < L.rows ; i++){ 159 | norm += L.vals[j + i * L.cols] * L.vals[j + i * L.cols]; 160 | } 161 | if(isDraw) document.write(norm + ", "); 162 | 163 | if(Math.abs(norm - 1) > test_cvTermCriteria.eps) 164 | throw "Lの各列ベクトルの大きさでエラー"; 165 | } 166 | if(isDraw) document.write("

"); 167 | 168 | if(isDraw) document.write("Rの列の大きさ
"); 169 | for(var j = 0 ; j < R.cols ; j++){ 170 | var norm = 0; 171 | for(var i = 0 ; i < R.rows ; i++){ 172 | norm += R.vals[j + i * R.cols] * R.vals[j + i * R.cols]; 173 | } 174 | if(isDraw) document.write(norm + ", "); 175 | 176 | if(Math.abs(norm - 1) > test_cvTermCriteria.eps) 177 | throw "Rの各列ベクトルの大きさでエラー"; 178 | } 179 | if(isDraw) document.write("

"); 180 | 181 | //直交性のチェック 182 | var rr = cvmMul(cvmTranspose(R), R); 183 | for(var i = 0 ; i < rr.rows*rr.cols ; i++){ 184 | if(rr.vals[i] < term.eps) rr.vals[i] = 0; 185 | } 186 | if(isDraw) cvDWriteMatrix(rr, "Rの直交性"); 187 | 188 | for(var i = 0 ; i < rr.rows ; i++){ 189 | for(var j = 0 ; j < rr.cols ; j++){ 190 | if(Math.abs(rr.vals[j + i * rr.cols] - (i == j ? 1 : 0)) > test_cvTermCriteria.eps) 191 | throw "Rの直交性の大きさでエラー"; 192 | } 193 | } 194 | 195 | var ll = cvmMul(cvmTranspose(L), L); 196 | for(var i = 0 ; i < ll.rows*ll.cols ; i++){ 197 | if(ll.vals[i] < term.eps) ll.vals[i] = 0; 198 | } 199 | if(isDraw)cvDWriteMatrix(ll, "Lの直交性"); 200 | 201 | for(var i = 0 ; i < ll.rows ; i++){ 202 | for(var j = 0 ; j < ll.cols ; j++){ 203 | if(Math.abs(ll.vals[j + i * ll.cols] - (i == j ? 1 : 0)) > test_cvTermCriteria.eps) 204 | throw "Lの直交性でエラー"; 205 | } 206 | } 207 | 208 | 209 | //元に戻るか 210 | if(isDraw) document.write("元に戻るか
"); 211 | var ai = cvmMul(cvmMul(L, W), cvmTranspose(R)); 212 | 213 | if(isDraw) cvDWriteMatrix(ai, "LWRt"); 214 | 215 | var sabun = cvmSub(mat, ai); 216 | for(var i = 0 ; i < sabun.rows*sabun.cols ; i++){ 217 | if(sabun.vals[i] > test_cvTermCriteria.eps) 218 | throw "元に戻るかチェックでエラー"; 219 | } 220 | 221 | rtn = true; 222 | 223 | }catch(ex){ 224 | alert("test_cvmSVD " + ex); 225 | } 226 | 227 | if(isDraw){ 228 | cvDWriteMatrix(W, "W"); 229 | cvDWriteMatrix(L, "L"); 230 | cvDWriteMatrix(cvmTranspose(R), "R^tr"); 231 | } 232 | 233 | return rtn; 234 | } 235 | 236 | 237 | 238 | //cvmAddNewOrthogonalVecのテスト 239 | //入力 240 | //mat CvMat型 調べる行列 241 | //isDraw bool型 計算途中の配列を描画するか 242 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 243 | //出力 244 | //bool型 問題なければtrue 245 | function test_cvmAddNewOrthogonalVec(mat, isDraw, test_cvTermCriteria){ 246 | var rtn = false; 247 | try{ 248 | //そもそもmatは直交行列か 249 | for(var j = 0 ; j < mat.cols ; j++){ 250 | var vec1 = cvCreateMat(mat.rows, 1); 251 | for(var m = 0 ; m < vec1.rows ; m++){ 252 | vec1.vals[m] = mat.vals[j + m * mat.cols]; 253 | } 254 | for(var j2 = j + 1 ; j2 < mat.cols; j2++){ 255 | var vec2 = cvCreateMat(mat.rows, 1); 256 | for(var m = 0 ; m < vec2.rows ; m++){ 257 | vec2.vals[m] = mat.vals[j2 + m * mat.cols]; 258 | } 259 | var sum = 0; 260 | for(var m = 0 ; m < vec2.rows ; m++){ 261 | sum += vec1.vals[m] * vec2.vals[m]; 262 | } 263 | if(isDraw){ 264 | cvDWriteMatrix(cvmTranspose(vec1), "vec1"); 265 | cvDWriteMatrix(cvmTranspose(vec2), "vec2"); 266 | document.write("直交性判断 : " + sum + "

"); 267 | } 268 | 269 | if(Math.abs(sum) > test_cvTermCriteria.eps){ 270 | throw "そもそも直交じゃねえ!"; 271 | } 272 | } 273 | } 274 | 275 | var noVec = cvmAddNewOrthogonalVec(mat); 276 | 277 | if(isDraw) cvDWriteMatrix(cvmTranspose(noVec), "新しいベクトル"); 278 | 279 | //新しいベクトルの直交性判断 280 | for(var j = 0 ; j < mat.cols ; j++){ 281 | //既存ベクトル 282 | var vec1 = cvCreateMat(mat.rows, 1); 283 | for(var m = 0 ; m < vec1.rows ; m++){ 284 | vec1.vals[m] = mat.vals[j + m * mat.cols]; 285 | } 286 | if(isDraw) cvDWriteMatrix(cvmTranspose(vec1), "直交か判断するベクトル"); 287 | 288 | //内積 289 | var sum = 0; 290 | for(var m = 0 ; m < vec1.rows ; m++){ 291 | sum += noVec.vals[m] * vec1.vals[m]; 292 | } 293 | 294 | if(isDraw) document.write("直交性判断 : " + sum + "

"); 295 | if(Math.abs(sum) > test_cvTermCriteria.eps){ 296 | throw "新しいベクトルは直交じゃねえ!"; 297 | } 298 | } 299 | 300 | rtn = true; 301 | } 302 | catch(ex){ 303 | alert("test_cvmAddNewOrthogonalVec : " + ex); 304 | } 305 | return rtn; 306 | } 307 | 308 | 309 | //cvmInverseのテスト 310 | //入力 311 | //mat CvMat型 調べる行列 312 | //isDraw bool型 計算途中の配列を描画するか 313 | //cvTermCriteria CvTermCriteria型 計算精度 314 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 315 | //出力 316 | //bool型 問題なければtrue 317 | function test_cvmInverse(mat, isDraw, cvTermCriteria, test_cvTermCriteria){ 318 | try{ 319 | //デフォルト 320 | if(cvUndefinedOrNull(cvTermCriteria)) 321 | cvTermCriteria = new CvTermCriteria(); 322 | 323 | if(cvUndefinedOrNull(test_cvTermCriteria)) 324 | test_cvTermCriteria = new CvTermCriteria(); 325 | 326 | if(isDraw) cvDWriteMatrix(mat, "逆行列を求める行列"); 327 | 328 | var invM = cvmInverse(mat, cvTermCriteria); 329 | 330 | //逆行列のチェック 331 | if(mat.rows == mat.cols){ 332 | 333 | if(isDraw) cvDWriteMatrix(invM, "逆行列"); 334 | 335 | var mm = cvmMul(invM, mat); 336 | 337 | if(isDraw) cvDWriteMatrix(mm, "逆行列*行列"); 338 | 339 | 340 | for(var i = 0 ; i < mm.rows ; i++){ 341 | for(var j = 0 ; j < mm.cols ; j++){ 342 | if(Math.abs(mm.vals[j + i * mm.cols] + (i==j ? -1 : 0)) > test_cvTermCriteria.eps) 343 | return false; 344 | } 345 | } 346 | } 347 | //擬似逆行列のチェック 348 | else{ 349 | if(isDraw) cvDWriteMatrix(invM, "擬似逆行列"); 350 | 351 | //チェック1 352 | var mm = cvmMul(cvmMul(mat, invM), mat); 353 | 354 | if(isDraw) cvDWriteMatrix(mm, "行列 * 擬似逆行列 * 行列"); 355 | 356 | var sabun = cvmSub(mat, mm); 357 | 358 | for(var i = 0 ; i < sabun.rows ; i++){ 359 | for(var j = 0 ; j < sabun.cols ; j++){ 360 | if(Math.abs(sabun.vals[j + i * sabun.cols]) > test_cvTermCriteria.eps) 361 | return false; 362 | } 363 | } 364 | 365 | //チェック2 366 | mm = cvmMul(cvmMul(invM, mat), invM); 367 | 368 | if(isDraw) cvDWriteMatrix(mm, "擬似逆行列 * 行列 * 擬似逆行列"); 369 | 370 | sabun = cvmSub(invM, mm); 371 | 372 | for(var i = 0 ; i < sabun.rows ; i++){ 373 | for(var j = 0 ; j < sabun.cols ; j++){ 374 | if(Math.abs(sabun.vals[j + i * sabun.cols]) > test_cvTermCriteria.eps) 375 | return false; 376 | } 377 | } 378 | 379 | //チェック3 380 | mm = cvmMul(mat, invM); 381 | 382 | if(isDraw) cvDWriteMatrix(mm, "行列 * 擬似逆行列"); 383 | 384 | 385 | var mmtr = cvmTranspose(mm); 386 | 387 | sabun = cvmSub(mm, mmtr); 388 | 389 | for(var i = 0 ; i < sabun.rows ; i++){ 390 | for(var j = 0 ; j < sabun.cols ; j++){ 391 | if(Math.abs(sabun.vals[j + i * sabun.cols]) > test_cvTermCriteria.eps) 392 | return false; 393 | } 394 | } 395 | 396 | //チェック4 397 | mm = cvmMul(invM, mat); 398 | 399 | if(isDraw) cvDWriteMatrix(mm, "擬似逆行列 * 行列"); 400 | 401 | 402 | var mmtr = cvmTranspose(mm); 403 | 404 | sabun = cvmSub(mm, mmtr); 405 | 406 | for(var i = 0 ; i < sabun.rows ; i++){ 407 | for(var j = 0 ; j < sabun.cols ; j++){ 408 | if(Math.abs(sabun.vals[j + i * sabun.cols]) > test_cvTermCriteria.eps) 409 | return false; 410 | } 411 | } 412 | } 413 | } 414 | catch(ex){ 415 | alert("test_cvmInverse : " + ex); 416 | } 417 | 418 | return true; 419 | } 420 | 421 | //cvmQRのテスト 422 | //入力 423 | //mat CvMat型 調べる行列 424 | //isDraw bool型 計算途中の配列を描画するか 425 | //cvTermCriteria CvTermCriteria型 計算精度 426 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 427 | //出力 428 | //bool型 問題なければtrue 429 | function test_cvmQR(mat, isDraw, cvTermCriteria, test_cvTermCriteria){ 430 | var rtn = false; 431 | try{ 432 | //デフォルト 433 | if(cvUndefinedOrNull(cvTermCriteria)) 434 | cvTermCriteria = new CvTermCriteria(); 435 | 436 | if(cvUndefinedOrNull(test_cvTermCriteria)) 437 | test_cvTermCriteria = new CvTermCriteria(); 438 | 439 | var qr = cvmQR(mat, cvTermCriteria); 440 | 441 | var Q = qr[0]; 442 | var R = qr[1]; 443 | 444 | for(var i = 0 ; i < R.cols * R.rows ; i++){ 445 | if(Math.abs(R.vals[i]) < test_cvTermCriteria.eps) R.vals[i] = 0; 446 | } 447 | 448 | if(isDraw) cvDWriteMatrix(Q, "Q"); 449 | if(isDraw) cvDWriteMatrix(R, "R"); 450 | 451 | 452 | //----- Qの直交性のチェック [start]-------// 453 | var Qt = cvmTranspose(qr[0]); 454 | var QQt = cvmMul(Qt, Q); 455 | //閾値以下を0にする 456 | for(var i = 0 ; i < QQt.cols * QQt.rows ; i++){ 457 | if(Math.abs(QQt.vals[i]) < test_cvTermCriteria.eps) QQt.vals[i] = 0; 458 | } 459 | 460 | if(isDraw) cvDWriteMatrix(QQt, "QQt"); 461 | 462 | for(var i = 0 ; i < QQt.rows ; i++){ 463 | for(var j = 0 ; j < QQt.cols ; j++){ 464 | if(cvUndefinedOrNull(QQt.vals[j + i * QQt.cols])){ 465 | throw "Qの値がnullかundefined"; 466 | } 467 | if(i == j){ 468 | if(Math.abs(QQt.vals[j + i * QQt.cols] - 1) > test_cvTermCriteria.eps){ 469 | throw "Qの直交性のチェック"; 470 | } 471 | } 472 | else{ 473 | if(Math.abs(QQt.vals[j + i * QQt.cols]) > test_cvTermCriteria.eps){ 474 | throw "Qの直交性のチェック"; 475 | } 476 | } 477 | } 478 | } 479 | //----- Qの直交性のチェック [end]-------// 480 | 481 | 482 | //Rの三角化チェック 483 | for(var i = 1 ; i < R.rows ; i++){ 484 | for(var j = 0 ; j < i - 1 ; j++){ 485 | if(R.vals[j + i * R.cols] > test_cvTermCriteria.eps){ 486 | throw "Rの三角化のチェック"; 487 | } 488 | } 489 | } 490 | 491 | //元に戻るか 492 | var reverse = cvmMul(Qt, R); 493 | for(var i = 0 ; i < reverse.rows ; i++){ 494 | for(var j = 0 ; j < reverse.cols ; j++){ 495 | if(Math.abs(reverse.vals[j + i * reverse.cols] - mat.vals[j + i * mat.cols]) > test_cvTermCriteria.eps){ 496 | throw "M = QtRのチェック"; 497 | } 498 | } 499 | } 500 | 501 | rtn = true; 502 | } 503 | catch(ex){ 504 | alert("test_cvmQRでエラー : " + ex); 505 | } 506 | 507 | return rtn; 508 | } 509 | 510 | //cvmEigenの結果をテスト 511 | //入力 512 | //mat CvMat型 調べる行列 513 | //isDraw bool型 計算途中の配列を描画するか 514 | //cvTermCriteria CvTermCriteria型 計算精度 515 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 516 | //出力 517 | //bool型 問題なければtrue 518 | function test_cvmEigen(mat, isDraw, cvTermCriteria, test_cvTermCriteria){ 519 | try{ 520 | //デフォルト 521 | if(cvUndefinedOrNull(cvTermCriteria)) 522 | cvTermCriteria = new CvTermCriteria(); 523 | 524 | if(cvUndefinedOrNull(test_cvTermCriteria)) 525 | test_cvTermCriteria = new CvTermCriteria(); 526 | 527 | 528 | var ee = cvmEigen(mat, cvTermCriteria); 529 | if(!ee) return false; 530 | 531 | var eValues = ee[0]; 532 | var eVects = ee[1]; 533 | 534 | if(isDraw){ 535 | cvDWriteMatrix(eValues, "固有値"); 536 | cvDWriteMatrix(eVects, "固有ベクトル"); 537 | } 538 | 539 | if(isDraw) document.write("固有値と固有ベクトルのチェック
"); 540 | 541 | for(var v = 0 ; v < eValues.rows ; v++){ 542 | 543 | var eVect = cvCreateMat(eVects.rows, 1); 544 | for(var i = 0 ; i < eVect.rows ; i++){ 545 | eVect.vals[i] = eVects.vals[v + i * eVects.cols]; 546 | } 547 | 548 | if(isDraw){ 549 | document.write("固有値
"); 550 | document.write(eValues.vals[v] + "

"); 551 | cvDWriteMatrix(cvmTranspose(eVect), "固有ベクトル"); 552 | } 553 | 554 | var a = cvmMul(mat, eVect); 555 | 556 | for(var i = 0 ; i < eVect.rows ; i++){ 557 | eVect.vals[i] = eValues.vals[v] * eVect.vals[i]; 558 | } 559 | 560 | if(isDraw) cvDWriteMatrix(a, "mat * 固有ベクトル"); 561 | if(isDraw) cvDWriteMatrix(eVect, "固有値 * 固有ベクトル"); 562 | 563 | for(var i = 0 ; i < eVect.rows ; i++){ 564 | if(Math.abs(a.vals[i] - eVect.vals[i]) > test_cvTermCriteria.eps){ 565 | if(isDraw){ 566 | document.write(i +"列目
"); 567 | document.write("mat * 固有ベクトル - 固有値 * 固有ベクトル
"); 568 | document.write(Math.abs(a.vals[i] - eVect.vals[i]) + "
"); 569 | document.write("精度 = " + test_cvTermCriteria.eps + "

"); 570 | } 571 | return false; 572 | } 573 | } 574 | } 575 | } 576 | catch(ex){ 577 | alert("test_cvmEigen : " + ex); 578 | } 579 | 580 | return true; 581 | } 582 | 583 | //QR分解を利用した実対称行列の三重対角化 584 | //入力 585 | //mat CvMat型 調べる行列 586 | //isDraw bool型 計算途中の配列を描画するか 587 | //cvTermCriteria CvTermCriteria型 計算精度 588 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 589 | //出力 590 | //bool型 問題なければtrue 591 | 592 | function test_cvmTridiagonalization (mat, isDraw, cvTermCriteria, test_cvTermCriteria){ 593 | 594 | try{ 595 | //対称化のチェック 596 | for(var i = 0 ; i < mat.rows ; i++){ 597 | for(var j = i + 1 ; j < mat.cols ; j++){ 598 | if(mat.vals[j + i * mat.cols] != mat.vals[i + j *mat.cols]){ 599 | throw "matは対称行列ではありません"; 600 | } 601 | } 602 | } 603 | 604 | 605 | //バリデーション 606 | if(cvUndefinedOrNull(cvTermCriteria)) 607 | cvTermCriteria = new CvTermCriteria(); 608 | 609 | if(cvUndefinedOrNull(test_cvTermCriteria)) 610 | test_cvTermCriteria = new CvTermCriteria(); 611 | 612 | var rq = cvmCopy(mat); 613 | 614 | //---QR法による三重対角化--- 615 | var isOK = false; 616 | for(var loop = 0 ; loop < cvTermCriteria.max_iter ; loop++){ 617 | 618 | qr = cvmQR(rq); 619 | if(qr == null) return rtn; 620 | 621 | rq = cvmMul(qr[1],cvmTranspose(qr[0])); 622 | 623 | //精度のチェック(rqが三重対角行列か) 624 | isOK = true; 625 | for(var i = 0 ; i < rq.rows; i++){ 626 | for(var j = 0 ; j < rq.cols; j++){ 627 | if(i != j && i - 1 != j && i + 1 != j && Math.abs(rq.vals[j + i * rq.cols]) > cvTermCriteria.eps){ 628 | isOK = false; 629 | break; 630 | } 631 | } 632 | //精度のチェックでひっかかっているならループをぬける 633 | if(!isOK) break; 634 | } 635 | 636 | if(isDraw){ 637 | cvDWriteMatrix(qr[0], "Q"); 638 | cvDWriteMatrix(qr[1], "R"); 639 | cvDWriteMatrix(rq, "変換mat"); 640 | } 641 | 642 | //精度が問題なければfor文を抜ける 643 | if(isOK) break; 644 | } 645 | 646 | //精度が問題ないか 647 | if(!isOK){ 648 | throw "最大ループ回数(" + cvTermCriteria.max_iter + ")を超えましたが精度" + cvTermCriteria.eps + "が足りていません"; 649 | } 650 | } 651 | catch(ex){ 652 | alert("test_cvmTridiagonalization : " + ex); 653 | cvDWriteMatrix(rq, "変換mat"); 654 | return false; 655 | } 656 | return true; 657 | } 658 | 659 | 660 | //cvmLUの結果をテスト 661 | //入力 662 | //mat CvMat型 調べる行列 663 | //isDraw bool型 計算途中の配列を描画するか 664 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 665 | //出力 666 | //bool型 問題なければtrue 667 | function test_cvmLU(mat, isDraw, test_cvTermCriteria){ 668 | //バリデーション 669 | if(cvUndefinedOrNull(test_cvTermCriteria)) 670 | test_cvTermCriteria = new CvTermCriteria(); 671 | 672 | var LU = cvmLU(mat); 673 | var L = LU[0]; 674 | var U = LU[1]; 675 | 676 | if(isDraw) cvDWriteMatrix(L, "下三角行列"); 677 | if(isDraw) cvDWriteMatrix(U, "上三角行列"); 678 | 679 | for(var j = 0 ; j < L.cols - 1 ; j++){ 680 | //下三角か 681 | for(var i = 0 ; i < j ; i++){ 682 | if(Math.abs(L.vals[j + i * L.cols]) > test_cvTermCriteria.eps){ 683 | return false; 684 | } 685 | } 686 | //上三角か 687 | for(var i = j + 1 ; i < U.rows ; i++){ 688 | if(Math.abs(U.vals[j + i * U.cols]) > test_cvTermCriteria.eps){ 689 | return false; 690 | } 691 | } 692 | } 693 | 694 | //元に戻るか 695 | if(isDraw) document.write("元に戻るか
"); 696 | var ai = cvmMul(L, U); 697 | 698 | if(isDraw) cvDWriteMatrix(ai, "LU"); 699 | 700 | var sabun = cvmSub(mat, ai); 701 | 702 | for(var i = 0 ; i < sabun.rows*sabun.cols ; i++){ 703 | if(sabun.vals[i] > test_cvTermCriteria.eps) 704 | return false; 705 | } 706 | 707 | return true; 708 | } 709 | 710 | //cvmLUの結果をテスト 711 | //入力 712 | //vec1 CvMat型 調べる行列 713 | //vec2 CvMat型 調べる行列 714 | //isDraw bool型 計算途中の配列を描画するか 715 | //test_cvTermCriteria CvTermCriteria型 計算が合っているかを確認する精度 716 | //出力 717 | //bool型 問題なければtrue 718 | function test_cvmHouseHolder(vec1, vec2, isDraw, test_cvTermCriteria){ 719 | //バリデーション 720 | if(cvUndefinedOrNull(test_cvTermCriteria)) 721 | test_cvTermCriteria = new CvTermCriteria(); 722 | 723 | 724 | var hh = cvmHouseHolder(vec1, vec2); 725 | 726 | if(isDraw) cvDWriteMatrix(hh, "householder"); 727 | 728 | //直交行列か 729 | var imat = cvmMul(hh, cvmTranspose(hh)); 730 | 731 | if(isDraw){ 732 | document.write("直交性のチェック
"); 733 | cvDWriteMatrix(imat, "h*ht"); 734 | } 735 | 736 | for(var i = 0 ; i < imat.rows ; i++){ 737 | for(var j = 0 ; j < imat.cols ; j++){ 738 | if((i == j && Math.abs(imat.vals[j + i * imat.cols] - 1) > test_cvTermCriteria.eps) 739 | ||(i != j && Math.abs(imat.vals[j + i * imat.cols]) > test_cvTermCriteria.eps)){ 740 | return false; 741 | } 742 | } 743 | } 744 | 745 | //差がないか 746 | if(isDraw) document.write("差がないか
"); 747 | 748 | var a = cvmMul(hh, vec1); 749 | var b = cvmMul(hh, vec2); 750 | 751 | if(isDraw) cvDWriteMatrix(a, "hh * vec1"); 752 | if(isDraw) cvDWriteMatrix(b, "hh * vec2"); 753 | 754 | var sabun = cvmSub(a, vec2); 755 | 756 | for(var i = 0 ; i < sabun.rows*sabun.cols ; i++){ 757 | if(Math.abs(sabun.vals[i]) > test_cvTermCriteria.eps) 758 | return false; 759 | } 760 | 761 | sabun = cvmSub(b, vec1); 762 | 763 | for(var i = 0 ; i < sabun.rows*sabun.cols ; i++){ 764 | if(Math.abs(sabun.vals[i]) > test_cvTermCriteria.eps) 765 | return false; 766 | } 767 | 768 | return true; 769 | } 770 | 771 | -------------------------------------------------------------------------------- /opencv.js: -------------------------------------------------------------------------------- 1 | 2 | //外部jsの読み込み 3 | document.write(''); 4 | document.write(''); 5 | document.write(''); 6 | document.write(''); 7 | document.write(''); 8 | 9 | //開発中メソッド 10 | document.write(''); 11 | 12 | //test用メソッド 13 | document.write(''); 14 | 15 | //メモ 16 | //imgタグの画像から直接IplImage型へは変換できない 17 | //ローカルの画像ファイルはクロスドメイン扱いとなりjavascriptのエラーが出る --------------------------------------------------------------------------------