├── 1505.06600v1.pdf ├── IMG_3430.MOV ├── Image.m ├── LICENSE ├── Line.m ├── README.md ├── TrianglesTree.m ├── createPatchMasks.m ├── getPrm.m ├── main.m ├── nonMaximalSupression.m ├── nonMaximalSupressionPlusPlus.m ├── pouriya nourizadeh ├── pouriya nuriadeh pp.pdf ├── pouriya nuriadeh.docx ├── runFastIm.m ├── runIm.m ├── runRealIm.m └── updateRespMapFunc.m /1505.06600v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdieslaminet/Image_Edge_Detection/6bc7f35caaf4beb8437dd50713058c60c2d4f71d/1505.06600v1.pdf -------------------------------------------------------------------------------- /IMG_3430.MOV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdieslaminet/Image_Edge_Detection/6bc7f35caaf4beb8437dd50713058c60c2d4f71d/IMG_3430.MOV -------------------------------------------------------------------------------- /Image.m: -------------------------------------------------------------------------------- 1 | classdef Image < handle 2 | %% properties 3 | properties(GetAccess = public) 4 | I 5 | resI 6 | resIgray 7 | param 8 | noiseSigma 9 | leftTree 10 | rightTree 11 | minLength 12 | treeDataCell 13 | lengthDataCell 14 | lowLevel 15 | maxContrast 16 | end 17 | 18 | properties(Constant) 19 | WIDTH = 1; 20 | IND_COL = 2; 21 | end 22 | 23 | %% methods 24 | methods (Access = public) 25 | function obj = Image(I,param,noiseSigma) 26 | obj.I = im2double(I); 27 | obj.param = param; 28 | obj.noiseSigma = noiseSigma; 29 | obj = obj.clearRes(); 30 | end 31 | 32 | function obj = buildTree(obj,triFlag) 33 | prm = getPrm(obj.param); 34 | obj.minLength = prm.minLength; 35 | [m,n] = size(obj.I); 36 | N = numel(obj.I); 37 | level = floor(log2(N))-1; 38 | if triFlag 39 | obj.leftTree = TrianglesTree([1,1],[m,1],[m,n],prm.minLength,obj.I,obj.param,level,obj.noiseSigma); 40 | obj.rightTree = TrianglesTree([m,n],[1,n],[1,1],prm.minLength,obj.I,obj.param,level,obj.noiseSigma); 41 | else 42 | obj.leftTree = TrianglesTree([1,n],[1,1],[m,1],prm.minLength,obj.I,obj.param,level,obj.noiseSigma); 43 | obj.rightTree = TrianglesTree([m,1],[m,n],[1,n],prm.minLength,obj.I,obj.param,level,obj.noiseSigma); 44 | end 45 | 46 | obj.treeDataCell = cell(1,level); 47 | obj.lengthDataCell = cell(1,level); 48 | 49 | curTree = obj.leftTree; 50 | for i=level:-1:1 51 | obj.lengthDataCell{i}.length = curTree.length; 52 | obj.lengthDataCell{i}.lengthHypo = curTree.lengthHypo; 53 | if curTree.isLeaf() 54 | break; 55 | end 56 | curTree = curTree.leftTree; 57 | end 58 | 59 | obj.lowLevel = i; 60 | obj.treeDataCell{i}.respMap = [obj.leftTree.respMap,obj.rightTree.respMap]; 61 | obj.treeDataCell{i}.respPixels = [obj.leftTree.respPixels,obj.rightTree.respPixels]; 62 | %obj = obj.updateFirstDataLevel(obj.leftTree); 63 | %obj = obj.updateFirstDataLevel(obj.rightTree); 64 | obj.maxContrast = zeros(1,2^level)-1; 65 | 66 | first = true; 67 | 68 | for i=i:level 69 | 70 | if ~first 71 | blockSize = obj.lengthDataCell{i-1}.length^2+2*obj.lengthDataCell{i-1}.length*obj.lengthDataCell{i-1}.lengthHypo; 72 | [obj.treeDataCell{i}.respMap obj.treeDataCell{i}.respPixels] = TrianglesTree.updateRespMapPlusPlus(obj.treeDataCell{i-1}.respMap,obj.param,obj.lengthDataCell{i}.length,obj.lengthDataCell{i}.lengthHypo,blockSize,i,N,obj.noiseSigma); 73 | obj.maxContrast(i) = max(abs(obj.treeDataCell{i}.respMap(TrianglesTree.C,:))); 74 | end 75 | 76 | curT = zeros(1,2^level)-1; 77 | curC = abs(obj.treeDataCell{i}.respMap(TrianglesTree.C,:)); 78 | curL = 0.5*obj.treeDataCell{i}.respMap(TrianglesTree.Ll,:)+0.5*obj.treeDataCell{i}.respMap(TrianglesTree.Lr,:); 79 | 80 | curL = round(curL); 81 | toRemove = (curL <= 0 | isnan(curL)); 82 | curL(toRemove) = []; 83 | curC(toRemove) = []; 84 | 85 | [curC,I] = sort(curC); 86 | curL = curL(I); 87 | 88 | curT(curL) = curC; 89 | obj.maxContrast = max(obj.maxContrast,curT); 90 | 91 | first = false; 92 | end 93 | end 94 | 95 | function obj = updateFirstDataLevel(obj,curTree) 96 | i = obj.lowLevel; 97 | if(curTree.isLeaf()) 98 | if isempty(obj.treeDataCell{i}) 99 | obj.treeDataCell{i}.respMap = curTree.respMap; 100 | obj.treeDataCell{i}.respPixels = curTree.respPixels; 101 | else 102 | obj.treeDataCell{i}.respMap = [obj.treeDataCell{i}.respMap curTree.respMap]; 103 | obj.treeDataCell{i}.respPixels = [obj.treeDataCell{i}.respPixels curTree.respPixels]; 104 | end 105 | else 106 | obj = obj.updateFirstDataLevel(curTree.leftTree); 107 | obj = obj.updateFirstDataLevel(curTree.rightTree); 108 | end 109 | end 110 | 111 | function obj = detectEdgesPlusPlus(obj) 112 | prm = getPrm(obj.param); 113 | len = length(obj.treeDataCell); 114 | edgesIndices = zeros(2,0); 115 | edgesScores = zeros(1,0); 116 | 117 | for i = len:-1:obj.lowLevel+1 118 | map = obj.treeDataCell{i}.respMap; 119 | if i0; 142 | map(:,~isEdge) = []; 143 | 144 | if prm.doMinContrastTest 145 | posContrast = map(TrianglesTree.C,:) > 0; 146 | posTest = map(TrianglesTree.minC,:) >= 0.5*map(TrianglesTree.C,:); 147 | negContrast = map(TrianglesTree.C,:) < 0; 148 | negTest = map(TrianglesTree.maxC,:) <= 0.5*map(TrianglesTree.C,:); 149 | minConstTest = (posContrast & posTest) | (negContrast & negTest); 150 | map(:,~minConstTest) = []; 151 | end 152 | 153 | %[m,n] = size(map); 154 | %fprintf('Level = %d Edges = %d\n',i,n); 155 | 156 | [Y,I1] = sort(map(TrianglesTree.NORM,:)); 157 | I1 = I1(end:-1:1); 158 | [Y,I2] = sort(map(TrianglesTree.S,I1)); 159 | I2 = I2(end:-1:1); 160 | map = map(:,I1(I2)); 161 | 162 | edgesNewIndices = map(TrianglesTree.bestLeft:TrianglesTree.bestRight,:); 163 | edgesNewScores = map(TrianglesTree.S,:); 164 | 165 | padd = size(edgesIndices,1)-size(edgesNewIndices,1); 166 | edgesNewIndices = [edgesNewIndices;zeros(padd,size(edgesNewIndices,2))]; 167 | edgesIndices = [edgesIndices edgesNewIndices]; 168 | 169 | edgesScores = [edgesScores edgesNewScores]; 170 | end 171 | pixels = obj.treeDataCell{obj.lowLevel}.respPixels; 172 | 173 | obj.resIgray = nonMaximalSupressionPlusPlus(edgesIndices,edgesScores,pixels,size(obj.resIgray),prm.nmsThres); 174 | 175 | if prm.normalizeScore 176 | obj.resIgray = Image.normalize(obj.resIgray); 177 | end 178 | end 179 | 180 | 181 | function obj = detectEdgesPlus(obj,nmsFlag) 182 | prm = getPrm(obj.param); 183 | len = length(obj.treeDataCell); 184 | indices = []; 185 | scores = []; 186 | norms = []; 187 | priorities = []; 188 | n0 = 0; 189 | lastPriority = 0; 190 | for i = len:-1:obj.lowLevel 191 | map = obj.treeDataCell{i}.respMap; 192 | map(TrianglesTree.Fl,:) = inf; 193 | map(TrianglesTree.NORM,indices) = norms; 194 | map(TrianglesTree.Fl,indices) = priorities; 195 | map(TrianglesTree.S,indices) = scores; 196 | 197 | if i == obj.lowLevel 198 | map(TrianglesTree.S,:) = -1; 199 | map(TrianglesTree.S,indices) = scores; 200 | break; 201 | end 202 | 203 | isEdge = map(TrianglesTree.S,:)>0; 204 | validEdges = false(size(isEdge)); 205 | validEdges(indices) = true; 206 | map(:,~isEdge) = []; 207 | validEdges(~isEdge) = []; 208 | 209 | if prm.doMinContrastTest 210 | posContrast = map(TrianglesTree.C,:) > 0; 211 | posTest = map(TrianglesTree.minC,:) >= 0.5*map(TrianglesTree.C,:); 212 | negContrast = map(TrianglesTree.C,:) < 0; 213 | negTest = map(TrianglesTree.maxC,:) <= 0.5*map(TrianglesTree.C,:); 214 | minConstTest = (posContrast & posTest) | (negContrast & negTest); 215 | 216 | map(:,~minConstTest & ~validEdges) = []; 217 | end 218 | 219 | [m,n] = size(map); 220 | fprintf('Level = %d Edges = %d\n',i,n-n0); 221 | n0 = n; 222 | 223 | %[Y,I1] = sort(map(TrianglesTree.NORM,:)); 224 | %I1 = I1(end:-1:1); 225 | [Y,I2] = sort(map(TrianglesTree.S,:)); 226 | I2 = I2(end:-1:1); 227 | curLength = length(I2); 228 | %map = map(:,I1); 229 | map = map(:,I2); 230 | 231 | indices = [map(TrianglesTree.bestLeft,:),map(TrianglesTree.bestRight,:)]; 232 | scores = [map(TrianglesTree.S,:),map(TrianglesTree.S,:)]; 233 | norms = [map(TrianglesTree.NORM,:),map(TrianglesTree.NORM,:)]; 234 | curPriorities = [map(TrianglesTree.Fl,:),map(TrianglesTree.Fl,:)]; 235 | priorities = lastPriority+1:lastPriority+curLength; 236 | priorities = [priorities,priorities]; 237 | priorities = min(priorities,curPriorities); 238 | 239 | [scores,ind] = sort(scores); 240 | indices = indices(ind); 241 | norms = norms(ind); 242 | priorities = priorities(ind); 243 | 244 | lastPriority = curLength+lastPriority; 245 | end 246 | isEdge = map(TrianglesTree.S,:)>0; 247 | validLength = map(TrianglesTree.NORM,:) > prm.minContrast*2; 248 | if prm.eliminateShortEdges 249 | valid = validLength & isEdge; 250 | else 251 | valid = isEdge; 252 | end 253 | pixels = obj.treeDataCell{obj.lowLevel}.respPixels; 254 | map(:,~valid) = []; 255 | pixels(:,~valid) = []; 256 | 257 | 258 | %map = map(:,validLength); 259 | %pixels = pixels(:,validLength); 260 | 261 | %[Y,I1] = sort(map(TrianglesTree.NORM,:)); 262 | %I1 = I1(end:-1:1); 263 | %[Y,I2] = sort(map(TrianglesTree.S,I1)); 264 | %I2 = I2(end:-1:1); 265 | %map = map(:,I1); 266 | %map = map(:,I2); 267 | edgeValues = map(TrianglesTree.S,:); 268 | edgePriority = map(TrianglesTree.Fl,:); 269 | %pixels = pixels(:,I1); 270 | %pixels = pixels(:,I2); 271 | 272 | if nmsFlag 273 | obj.resIgray = nonMaximalSupression(pixels,edgeValues,edgePriority,size(obj.resIgray),prm.nmsThres); 274 | obj.resIgray = Image.normalize(obj.resIgray); 275 | return; 276 | end 277 | 278 | val = zeros(size(pixels)); 279 | val = bsxfun(@plus,val',edgeValues')'; 280 | pixels = pixels(:); 281 | val = val(:); 282 | nans = isnan(pixels) | (pixels == 0); 283 | pixels(nans) = []; 284 | val(nans) = []; 285 | curVal = zeros(size(obj.resIgray)); 286 | [Y,Ind] = sort(val); 287 | curVal(pixels(Ind)) = Y; 288 | %curVal(pixels) = val; 289 | obj.resIgray = curVal; 290 | obj.resIgray = Image.normalize(obj.resIgray); 291 | end 292 | 293 | function obj = detectEdges(obj,nmsFlag) 294 | len = length(obj.treeDataCell); 295 | for i = len:-1:obj.lowLevel+1 296 | map = obj.treeDataCell{i}.respMap; 297 | isEdge = map(TrianglesTree.S,:)>0; 298 | 299 | posContrast = map(TrianglesTree.C,:) > 0; 300 | posTest = map(TrianglesTree.minC,:)>=0.5*map(TrianglesTree.C,:); 301 | negContrast = map(TrianglesTree.C,:) < 0; 302 | negTest = map(TrianglesTree.maxC,:)<=0.5*map(TrianglesTree.C,:); 303 | 304 | minConstTest = (posContrast & posTest) | (negContrast & negTest); 305 | 306 | map(:,~isEdge | ~minConstTest) = []; 307 | %map(:,~isEdge) = []; 308 | 309 | %[Y,I1] = sort(map(TrianglesTree.NORM,:)); 310 | %I1 = I1(end:-1:1); 311 | %[Y,I2] = sort(map(TrianglesTree.S,I1)); 312 | %I2 = I2(end:-1:1); 313 | %map = map(:,I1); 314 | %map = map(:,I2); 315 | 316 | [m,n] = size(map); 317 | fprintf('Level = %d Edges = %d\n',i,n); 318 | 319 | for j=1:n 320 | obj = obj.addEdge(i,map(TrianglesTree.S,j),map(TrianglesTree.bestLeft,j),map(TrianglesTree.bestRight,j),nmsFlag); 321 | end 322 | end 323 | obj.resIgray = Image.normalize(obj.resIgray); 324 | end 325 | 326 | function obj = markLeftCorners(obj) 327 | cur = obj.leftTree; 328 | while ~isempty(cur) 329 | obj.resI(cur.p1(1),cur.p1(2),obj.IND_COL) = 1; 330 | obj.resI(cur.p2(1),cur.p2(2),obj.IND_COL) = 1; 331 | obj.resI(cur.p3(1),cur.p3(2),obj.IND_COL) = 1; 332 | cur = cur.leftTree; 333 | end 334 | end 335 | 336 | function obj = markRightCorners(obj) 337 | cur = obj.rightTree; 338 | while ~isempty(cur) 339 | obj.resI(cur.p1(1),cur.p1(2),obj.IND_COL) = 1; 340 | obj.resI(cur.p2(1),cur.p2(2),obj.IND_COL) = 1; 341 | obj.resI(cur.p3(1),cur.p3(2),obj.IND_COL) = 1; 342 | cur = cur.rightTree; 343 | end 344 | end 345 | 346 | function obj = markAllCorners(obj) 347 | obj = obj.markAllCornersHelp(obj.leftTree); 348 | obj = obj.markAllCornersHelp(obj.rightTree); 349 | end 350 | 351 | function obj = markAllEdges(obj) 352 | obj = obj.markAllEdgesHelp(obj.leftTree); 353 | obj = obj.markAllEdgesHelp(obj.rightTree); 354 | obj.resIgray = obj.resIgray./max(obj.resIgray(:)); 355 | end 356 | 357 | function obj = showAllEdges(obj,depth) 358 | end 359 | 360 | function prob = onEdgeProb(obj,x) 361 | prm = getPrm(obj.params); 362 | s = prm.s; 363 | p = prm.p; 364 | alpha = prm.alpha; 365 | z = 2*s/p*gamma(1/p)-alpha*(1+exp(-(alpha/s)^p)); 366 | prob = -abs(x./s).^p-log(z); 367 | prob(abs(x)<=alpha) = -inf; 368 | end 369 | function prob = onEdgeGaussProb(obj,x,sigma) 370 | prob = log(normpdf(x,0,sigma)); 371 | end 372 | function prob = onEdgeUniformProb(obj,x,a,b) 373 | a = a/2; 374 | b = b/2; 375 | inRange = (abs(x)<=b) & (abs(x) >=a); 376 | prob = log(inRange./(2*(b-a))); 377 | end 378 | function prob = offEdgeNoiseProb(obj,x,len) 379 | prm = getPrm(obj.params); 380 | w = sum(abs(prm.filter)>0); 381 | sigmaL = obj.noiseSigma^2/(w*len); 382 | prob = -0.5*log(2*pi*sigmaL)-x.^2/(2*sigmaL); 383 | end 384 | function prob = offEdgeProb(obj,x,len) 385 | prm = getPrm(obj.params); 386 | s = prm.sBack/len; 387 | p = prm.pBack; 388 | z = 2*s/p*gamma(1/p); 389 | prob = -abs(x./s).^p-log(z); 390 | end 391 | function obj = clearRes(obj) 392 | [m,n] = size(obj.I); 393 | obj.resI = zeros(m,n,3); 394 | obj.resIgray = zeros(m,n); 395 | obj.resI(:,:,1) = obj.I; 396 | obj.resI = ntsc2rgb(obj.resI); 397 | end 398 | end 399 | 400 | methods (Access = private) 401 | 402 | function obj = addEdge(obj,level,score,leftInd,rightInd,nmsFlag) 403 | obj = obj.addEdgeHelp(level-1,score,leftInd,nmsFlag); 404 | if rightInd~=leftInd 405 | obj = obj.addEdgeHelp(level-1,score,rightInd,nmsFlag); 406 | end 407 | end 408 | 409 | function obj = addEdgeHelp(obj,level,score,ind,nmsFlag) 410 | if level == obj.lowLevel 411 | curVal = zeros(size(obj.resIgray)); 412 | pixels = obj.treeDataCell{level}.respPixels(:,ind); 413 | pixels(isnan(pixels) | pixels == 0) = []; 414 | curVal(pixels) = score; 415 | newPixels = curVal>0; 416 | L = sum(newPixels(:)); 417 | newPixels = imdilate(newPixels>0,true(3)); 418 | oldPixels = imdilate(obj.resIgray>0,true(3)); 419 | coor = newPixels & oldPixels; 420 | coor = sum(coor(:)); 421 | if coor/L<2 || ~nmsFlag 422 | obj.resIgray = max(obj.resIgray,curVal); 423 | end 424 | return; 425 | end 426 | obj.treeDataCell{level}.respMap(TrianglesTree.S,ind) = -1; 427 | leftInd = obj.treeDataCell{level}.respMap(TrianglesTree.bestLeft,ind); 428 | rightInd = obj.treeDataCell{level}.respMap(TrianglesTree.bestRight,ind); 429 | 430 | obj = obj.addEdgeHelp(level-1,score,leftInd,nmsFlag); 431 | 432 | if rightInd~=leftInd 433 | obj = obj.addEdgeHelp(level-1,score,rightInd,nmsFlag); 434 | end 435 | end 436 | 437 | function obj = markAllCornersHelp(obj,cur) 438 | if isempty(cur) 439 | return; 440 | end 441 | 442 | obj.resI(cur.p1(1),cur.p1(2),obj.IND_COL) = 1; 443 | obj.resI(cur.p2(1),cur.p2(2),obj.IND_COL) = 1; 444 | obj.resI(cur.p3(1),cur.p3(2),obj.IND_COL) = 1; 445 | 446 | obj = obj.markAllCornersHelp(cur.leftTree); 447 | obj = obj.markAllCornersHelp(cur.rightTree); 448 | end 449 | 450 | function obj = markAllEdgesHelp(obj,cur) 451 | if ~cur.isLeaf() 452 | edgePixels = cur.edgePixels; 453 | edgeValues = cur.edgeMap(cur.S,:); 454 | 455 | edgeLength = 0.5*cur.edgeMap(cur.Lr,:)+0.5*cur.edgeMap(cur.Ll,:); 456 | validLength = edgeLength >= obj.minLength; 457 | isEdge = edgeValues > 0; 458 | edgePixels = edgePixels(:,isEdge); 459 | edgeValues = edgeValues(:,isEdge); 460 | val = zeros(size(edgePixels)); 461 | val = bsxfun(@plus,val',edgeValues')'; 462 | nans = isnan(edgePixels) | edgePixels == 0; 463 | edgePixels(nans) = []; 464 | val(nans) = []; 465 | curVal = zeros(size(obj.resIgray)); 466 | [Y,I] = sort(val); 467 | curVal(edgePixels(I)) = Y; 468 | obj.resIgray = max(obj.resIgray,curVal); 469 | obj = obj.markAllEdgesHelp(cur.leftTree); 470 | obj = obj.markAllEdgesHelp(cur.rightTree); 471 | end 472 | end 473 | 474 | function obj = showAllEdgesHelp(obj,cur,str,depth) 475 | figure('name',str); 476 | [m,n] = size(cur.edgePixels); 477 | for i = 1:n 478 | pix = cur.edgePixels(:,i); 479 | pix(isnan(pix) | pix == 0) = []; 480 | obj.resIgray(pix) = 1; 481 | subplot(ceil(n/9),9,i); 482 | imshow(obj.resIgray); 483 | obj = obj.clearRes(); 484 | end 485 | 486 | if ~cur.isLeaf() && depth>0 487 | obj = obj.showAllEdgesHelp(cur.leftTree, strcat(str,'l '),depth-1); 488 | obj = obj.showAllEdgesHelp(cur.rightTree, strcat(str,'r '),depth-1); 489 | end 490 | end 491 | end 492 | 493 | methods(Static) 494 | function I = normalize(I) 495 | I = im2double(I); 496 | I = I-min(I(:)); 497 | I = I/max(I(:)); 498 | end 499 | end 500 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 mahdieslaminet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Line.m: -------------------------------------------------------------------------------- 1 | classdef Line 2 | %LINE 2D line class with applicative methods for images. 3 | properties(GetAccess = public) 4 | % cooridinates of the line, Matlab matrix axes 5 | x0 6 | x1 7 | y0 8 | y1 9 | width % odd number 10 | xPixels % x pixels of the whole line 11 | yPixels % y pixels 12 | xPoints % x exact points of the whole line 13 | yPoints % y points 14 | end 15 | properties(Constant) 16 | WHITE = 1; 17 | end 18 | properties(Dependent) 19 | end 20 | 21 | methods 22 | % Constructor 23 | function obj = Line(x0,y0,x1,y1,w) 24 | obj.x0 = x0;obj.x1 = x1;obj.y0 = y0;obj.y1 = y1; 25 | if(mod(w,2) == 0) 26 | w = w+1; 27 | end 28 | obj.width = w; 29 | obj = obj.calcPixels(); 30 | end 31 | 32 | % calculates the line pixels in the image 33 | function obj = calcPixels(obj) 34 | x0 = obj.x0;x1 = obj.x1;y0 = obj.y0;y1 = obj.y1; 35 | dx = abs(x1-x0); 36 | dy = abs(y1-y0); 37 | L = max(dx,dy); 38 | index = 1; 39 | obj.xPixels = zeros(1,L+1); 40 | obj.yPixels = zeros(1,L+1); 41 | 42 | if x0 < x1 43 | sx = 1; 44 | else 45 | sx = -1; 46 | end 47 | 48 | if y0 < y1 49 | sy = 1; 50 | else 51 | sy = -1; 52 | end 53 | 54 | err = dx-dy; 55 | 56 | while 1>0 57 | obj.xPixels(index) = x0; 58 | obj.yPixels(index) = y0; 59 | index = index+1; 60 | 61 | if x0 == x1 && y0 == y1 62 | break; 63 | end 64 | 65 | e2 = 2*err; 66 | 67 | if e2 > -dy 68 | err = err - dy; 69 | x0 = x0 + sx; 70 | end 71 | if e2 < dx 72 | err = err + dx; 73 | y0 = y0 + sy; 74 | end 75 | end 76 | end 77 | 78 | % calculates the line points, geometricaly 79 | function obj = calcPoints(obj) 80 | x0 = obj.x0;x1 = obj.x1;y0 = obj.y0;y1 = obj.y1; 81 | v = [x1-x0,y1-y0]; 82 | L = norm(v); 83 | v = v/L; 84 | obj.xPoints =zeros(1,L+1); 85 | obj.yPoints = zeros(1,L+1); 86 | 87 | for i=0:L 88 | pos = v*i; 89 | obj.xPoints(i+1) = x0+pos(1); 90 | obj.yPoints(i+1) = y0+pos(2); 91 | end 92 | 93 | obj.xPoints(end) = round(obj.xPoints(end)); 94 | obj.yPoints(end) = round(obj.yPoints(end)); 95 | end 96 | 97 | % returns a binary image of the line, MxN size. Assumes that 98 | % calcPoints was called before. 99 | function I = getLineImage(obj,M,N) 100 | I = zeros(M,N); 101 | %shift = obj.getShift(); 102 | for i=1:obj.width 103 | %loc = (obj.width+1)/2-i; 104 | %loc = loc*shift; 105 | loc = [0,0]; 106 | %if obj.inRange(M,N,obj.xPixels+loc(1),obj.yPixels+loc(2)) 107 | ind = sub2ind(size(I),obj.xPixels+loc(1),obj.yPixels+loc(2)); 108 | I(ind) = obj.WHITE; 109 | %end 110 | end 111 | I(obj.x0,obj.y0) = obj.WHITE; 112 | I(obj.x1,obj.y1) = obj.WHITE; 113 | end 114 | 115 | % returns a binary image of the edges of the line, 2 lines of width 116 | % 2 parallel the the original line, MxN size. Assumes that 117 | % calcPoints was called before. 118 | function E = getEdgeImage(obj,M,N) 119 | E = zeros(M,N); 120 | shift = obj.getShift(); 121 | w = (obj.width-1)/2; 122 | edges = [-w,w]; 123 | for i=1:length(edges) 124 | loc = edges(i); 125 | loc = loc*shift; 126 | ind = sub2ind(size(E),obj.xPixels(1:end)+loc(1),obj.yPixels(1:end)+loc(2)); 127 | E(ind) = obj.WHITE; 128 | 129 | end 130 | end 131 | 132 | function E = getEdgeFilter(obj,M,N) 133 | E = zeros(M,N); 134 | %shift = obj.getShift(); 135 | vec = [obj.x1-obj.x0,obj.y1-obj.y0]; 136 | vec = [0 -1; 1 0]*vec'; 137 | if abs(vec(1))>abs(vec(2)) 138 | vec(2) = 0; 139 | else 140 | vec(1) = 0; 141 | end 142 | vec = vec./norm(vec); 143 | shift = round(vec); 144 | 145 | w = (obj.width-1)/2; 146 | edges = [-w:-1,1:w]; 147 | for i=1:length(edges) 148 | loc = edges(i); 149 | loc = loc*shift; 150 | ind = sub2ind(size(E),obj.xPixels(2:end-1)+loc(1),obj.yPixels(2:end-1)+loc(2)); 151 | ind2 = sub2ind(size(E),obj.xPixels(1)+loc(1),obj.yPixels(1)+loc(2)); 152 | ind3 = sub2ind(size(E),obj.xPixels(end)+loc(1),obj.yPixels(end)+loc(2)); 153 | E(ind) = 0.5*obj.WHITE*sign(edges(i)); 154 | E(ind2) = 0.5*0.5*obj.WHITE*sign(edges(i)); 155 | E(ind3) = 0.5*0.5*obj.WHITE*sign(edges(i)); 156 | end 157 | end 158 | 159 | 160 | 161 | % samples the points along the line in image I, width w. Using 162 | % Interp2. Assumes that calcPoints() was called before. 163 | function S = samplePoints(obj,I,w) 164 | normal = obj.getNormal(); 165 | S = zeros(2*w,length(obj.xPoints)); 166 | index = 1; 167 | for i=-w:w 168 | if(i == 0) 169 | continue; 170 | end 171 | shift = normal*i; 172 | S(index,:) = interp2(I',obj.xPoints+shift(1),obj.yPoints+shift(2)); 173 | index = index+1; 174 | end 175 | end 176 | 177 | % returns the normalized normal off the line. 178 | function normal = getNormal(obj) 179 | lineDir = getLineDir(obj); 180 | if lineDir(2) == 0 181 | normal = [0 1]; 182 | else 183 | normal = [1 -lineDir(1)/lineDir(2)]; 184 | end 185 | normal = normal/norm(normal); 186 | end 187 | 188 | % return the normalized direction of the line 189 | function lineDir = getLineDir(obj) 190 | x0 = obj.x0;x1 = obj.x1;y0 = obj.y0;y1 = obj.y1; 191 | lineDir = [x1-x0,y1-y0]; 192 | lineDir = lineDir/norm(lineDir); 193 | end 194 | 195 | % sets the width of the line 196 | function obj = setWidth(obj,width) 197 | obj.width = width; 198 | end 199 | 200 | % return the shift in points in order to draw a line with width 201 | function shift = getShift(obj) 202 | normal = getNormal(obj); 203 | shift = abs(normal); 204 | if shift(1)>shift(2) 205 | shift(2) = 0; 206 | else 207 | shift(1) = 0; 208 | end 209 | shift = round(shift); 210 | end 211 | 212 | % return the length of the line 213 | function length = getLength(obj) 214 | v = [obj.x1-obj.x0,obj.y1-obj.y0]; 215 | length = norm(v); 216 | end 217 | end 218 | 219 | methods (Static) 220 | % return true of the x,y coordinate are in Range of an m x n image. 221 | function res = inRange(m,n,x,y) 222 | res = all(x>1 & y>0 & x<=m & y<=n); 223 | end 224 | end 225 | 226 | end 227 | 228 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Image_Edge_Detection 2 | تشخيص لبه هاي تصوير و از بين بردن نويز 3 | 4 | #Introduction: 5 | 6 | My project is related to the detection of image edges and removing image noise with the help of programming codes 7 | 8 | main.m: 9 | 10 | This file is derived from the original codes that we can run in MATLAB and other programs. 11 | 12 | line.m: 13 | 14 | This file is derived from codes and a series of tricks in programming 15 | 16 | image.m: 17 | 18 | We have used three images in this folder to test the coding and in these images we find the edges of the image and remove their noises. 19 | 20 | links drive: 21 | https://drive.google.com/file/d/1UrcXHfKeTE6Oo0exRZquc1howdVXuDLA/view?usp=drivesdk 22 | https://drive.google.com/file/d/1cED4vFlycla2TtapptGwIjFD2u6WnfNN/view?usp=drivesdk 23 | https://drive.google.com/file/d/1EwSL4G1U1LU59XynhGoIbd_ifwpFWELo/view?usp=drivesdk 24 | https://docs.google.com/file/d/1NnElBGJ5zfsOhQhSmzhilndzmJ9mOpKZ/edit?usp=docslist_api&filetype=msword 25 | 26 | pouriya nourizadeh.docx: 27 | 28 | This file is an example of paraphrased article in coding and article 29 | 30 | pouriya nourizadeh.pp: 31 | 32 | This file is an updated article 33 | 34 | Main article: 35 | 36 | In our main article, there have been many discussions about how to remove image noises and identify the edges of the image and create a clear image for the viewer, and a series of functions and formulas have been used to prove this claim. 37 | 38 | email: 39 | 40 | 021.poriyanori@gmail.com 41 | 42 | With great thanks and appreciation from the hardworking and kind teacher Mr. Mehdi Islami 43 | -------------------------------------------------------------------------------- /TrianglesTree.m: -------------------------------------------------------------------------------- 1 | classdef TrianglesTree < handle 2 | % TRIANGLESTREE Data Structure of image triangles tree tiling 3 | % |p2-p1| = |p2-p3| = |p3-p1|/sqrt(2) 4 | properties 5 | 6 | % triangle vertices 7 | p1 8 | p2 9 | p3 10 | 11 | % 2 sub triangle 12 | leftTree 13 | rightTree 14 | 15 | % responses data, S rows, number of edges indices columuns 16 | respMap 17 | edgeMap 18 | respPixels 19 | edgePixels 20 | 21 | % length of a triangle edge in pixels 22 | length 23 | 24 | %length of a triangle hypotenus in pixels 25 | lengthHypo 26 | 27 | % the edges vectors 28 | edgeVecCell 29 | edgeVecStartCell 30 | 31 | % parameter index 32 | param 33 | 34 | % level index 35 | level 36 | 37 | % number of pixels in the original image 38 | N 39 | 40 | % noise standart deviation 41 | sigma 42 | end 43 | 44 | properties(Constant) 45 | Fr = 1; 46 | Lr = 2; 47 | Fl = 3; 48 | Ll = 4; 49 | C = 5; 50 | minC = 6; 51 | maxC = 7; 52 | NORM = 8; 53 | bestLeft = 9; 54 | bestRight = 10; 55 | thetaBegin = 11; 56 | thetaEnd = 12; 57 | turnSqr = 13; 58 | turnNum = 14; 59 | S = 15; 60 | end 61 | 62 | methods (Access = public) 63 | 64 | function obj = TrianglesTree(p1,p2,p3,minLength,I,param,level,sigma) 65 | 66 | obj.p1 = p1; 67 | obj.p2 = p2; 68 | obj.p3 = p3; 69 | obj.length = max(abs(p2(1)-p1(1)),abs(p2(2)-p1(2)))+1; 70 | obj.lengthHypo = max(abs(p3(1)-p1(1)),abs(p3(2)-p1(2)))+1; 71 | obj.respMap = zeros(obj.S,obj.getNumOfEdges()); 72 | %obj.respPixels = cell(1,obj.getNumOfEdges()); 73 | %obj.respPixels = zeros(2^(level-3)*minLength,obj.getNumOfEdges()); 74 | obj.param = param; 75 | obj.level = level; 76 | obj.N = numel(I); 77 | obj.sigma = sigma; 78 | obj = obj.updateEdgeVectors(); 79 | 80 | if(obj.length <= minLength && (p1(1) == p2(1) || p1(2) == p2(2))) 81 | obj.leftTree = []; 82 | obj.rightTree = []; 83 | obj = obj.updateRespMapFirstLevel(I); 84 | else 85 | midPoint = round((p1+p3)/2); 86 | obj.leftTree = TrianglesTree(p2,midPoint,p1,minLength,I,param,level-1,sigma); 87 | obj.rightTree = TrianglesTree(p3,midPoint,p2,minLength,I,param,level-1,sigma); 88 | 89 | fname = sprintf('Files/level%d_%d.mat',obj.length,obj.lengthHypo); 90 | obj.checkIfExistsMatFile(fname); 91 | 92 | obj.respMap = [obj.leftTree.respMap, obj.rightTree.respMap]; 93 | obj.respPixels = [obj.leftTree.respPixels, obj.rightTree.respPixels]; 94 | %obj = obj.updateRespMap(false,fname); 95 | %obj = obj.updateRespMapPlus(fname); 96 | end 97 | 98 | %obj = obj.markEdges(); 99 | end 100 | 101 | function res = isLeaf(obj) 102 | res = isempty(obj.leftTree) && isempty(obj.rightTree); 103 | end 104 | 105 | function n = getNumOfEdges(obj) 106 | n = (obj.length)^2+2*obj.length*obj.lengthHypo; 107 | end 108 | 109 | end 110 | 111 | methods (Access = public) 112 | 113 | function checkIfExistsMatFile(obj,fname) 114 | if ~exist(fname, 'file') 115 | obj.createLevelMatFile(fname,true); 116 | end 117 | end 118 | 119 | 120 | function createLevelMatFile(obj,fname,mex) 121 | if mex 122 | res = createLevelMatFileFunc_mex( obj.length,obj.leftTree.length,obj.rightTree.length,obj.lengthHypo,obj.leftTree.lengthHypo,obj.rightTree.lengthHypo,obj.getNumOfEdges() ); 123 | save(fname,'res'); 124 | return 125 | end 126 | curSize = obj.leftTree.length*2; 127 | res = zeros(curSize,obj.getNumOfEdges()); 128 | 129 | % first edges pair 130 | edge1 = 0; 131 | edge2 = 1; 132 | sign1 = -1; 133 | el1 = 0; 134 | el2 = 2; 135 | sign2 = 1; 136 | er1 = 1; 137 | er2 = 2; 138 | len1 = obj.length; 139 | len2 = obj.length; 140 | subLenLeft = obj.leftTree.length-1; 141 | subLenRight = obj.rightTree.length-1; 142 | 143 | for v1 = 0:len1-1 144 | for v2 = 0:len2-1 145 | vl = v1; 146 | vr = v2; 147 | ind = obj.getIndexFromEdge(edge1,v1,edge2,v2,obj.length,obj.lengthHypo); 148 | arr = zeros(curSize,1); 149 | for vmid = 0:subLenLeft 150 | indl = obj.getIndexFromEdge(el1,subLenLeft-vmid,el2,vl,subLenLeft+1,obj.leftTree.lengthHypo); 151 | indr = obj.getIndexFromEdge(er1,vmid,er2,vr,subLenRight+1,obj.rightTree.lengthHypo); 152 | %res{ind} = [res{ind} sign1*indl sign2*indr]; 153 | arr(vmid*2+1:vmid*2+2,1) = [sign1*indl ;sign2*indr]; 154 | end 155 | res(:,ind) = arr; 156 | end 157 | end 158 | 159 | % second edges pair 160 | edge1 = 0; 161 | edge2 = 2; 162 | sign1 = -1; 163 | el1 = 0; 164 | el2 = 2; 165 | sign2 = -1; 166 | er1 = 0; 167 | er2 = 1; 168 | len1 = obj.length; 169 | len2 = obj.rightTree.length; 170 | gap = floor(obj.lengthHypo/2); 171 | subLenLeft = obj.leftTree.length-1; 172 | subLenRight = obj.rightTree.length-1; 173 | 174 | for v1 = 0:len1-1 175 | for v2 = 0:len2-1 176 | ind = obj.getIndexFromEdge(edge1,v1,edge2,v2,obj.length,obj.lengthHypo); 177 | arr = zeros(curSize,1); 178 | vl = v1; 179 | vr = v2; 180 | for vmid = 0:subLenLeft 181 | indl = obj.getIndexFromEdge(el1,vmid,el2,vl,subLenLeft+1,obj.leftTree.lengthHypo); 182 | indr = obj.getIndexFromEdge(er1,vr,er2,subLenRight-vmid,subLenLeft+1,obj.rightTree.lengthHypo); 183 | %res{ind} = [res{ind} sign1*indl sign2*indr]; 184 | arr(vmid*2+1:vmid*2+2,1) = [sign1*indl; sign2*indr]; 185 | end 186 | res(:,ind) = arr; 187 | end 188 | 189 | for v2 = len2:obj.lengthHypo-1 190 | ind = obj.getIndexFromEdge(edge1,v1,edge2,v2,obj.length,obj.lengthHypo); 191 | indl = obj.getIndexFromEdge(1,v2-gap,2,v1,subLenLeft+1,obj.leftTree.lengthHypo); 192 | %res{ind} = [res{ind} sign1*indl nan]; 193 | res(1:2,ind) = [sign1*indl; nan]; 194 | end 195 | end 196 | 197 | % third edges pair 198 | edge1 = 1; 199 | edge2 = 2; 200 | sign1 = 1; 201 | el1 = 0; 202 | el2 = 1; 203 | sign2 = -1; 204 | er1 = 1; 205 | er2 = 2; 206 | len1 = obj.length; 207 | len2 = obj.leftTree.length; 208 | gap = floor(obj.lengthHypo/2); 209 | subLenLeft = obj.leftTree.length-1; 210 | subLenRight = obj.rightTree.length-1; 211 | 212 | for v1 = 0:len1-1 213 | for v2 = gap:len2-1+gap 214 | ind = obj.getIndexFromEdge(edge1,v1,edge2,v2,obj.length,obj.lengthHypo); 215 | arr = zeros(curSize,1); 216 | vr = v1; 217 | vl = v2-gap; 218 | for vmid = 0:subLenLeft 219 | indl = obj.getIndexFromEdge(el1,vmid,el2,vl,subLenLeft+1,obj.leftTree.lengthHypo); 220 | indr = obj.getIndexFromEdge(er1,subLenRight-vmid,er2,vr,subLenRight+1,obj.rightTree.lengthHypo); 221 | %res{ind} = [res{ind} sign1*indl sign2*indr]; 222 | arr(vmid*2+1:vmid*2+2,1) = [sign1*indl ; sign2*indr]; 223 | end 224 | res(:,ind) = arr; 225 | end 226 | 227 | for v2 = 0:gap-1 228 | ind = obj.getIndexFromEdge(edge1,v1,edge2,v2,obj.length,obj.lengthHypo); 229 | indr = obj.getIndexFromEdge(0,v2,2,v1,subLenRight+1,obj.rightTree.lengthHypo); 230 | %res{ind} = [res{ind} nan sign2*indr]; 231 | res(1:2,ind) = [ nan; sign2*indr]; 232 | end 233 | end 234 | 235 | % save indices data 236 | save(fname,'res'); 237 | end 238 | 239 | function obj = updateRespMapFirstLevel(obj,I) 240 | prm = getPrm(obj.param); 241 | w = prm.filterWidth; 242 | m = mean(I(:)); 243 | Ior = I; 244 | str = 'symmetric'; 245 | %str = 'replicate'; 246 | I = padarray(padarray(I',w,str)',w,str); 247 | %I = padarray(I,[w w],'symmetric'); 248 | 249 | %if prm.padWithNan 250 | % I(1:w,:) = nan; 251 | % I(end-w+1:end,:) = nan; 252 | % I(:,1:w) = nan; 253 | % I(:,end-w+1:end) = nan; 254 | %end 255 | 256 | triangleOrientation = obj.getTriangleOrientation(); 257 | load(sprintf('Files/l%d.mat',triangleOrientation)); 258 | minCoords = min(min(obj.p1,obj.p2),obj.p3); 259 | maxCoords = max(max(obj.p1,obj.p2),obj.p3); 260 | gap = w; 261 | patch = I(minCoords(1)-w+gap:maxCoords(1)+w+gap,minCoords(2)-w+gap:maxCoords(2)+w+gap); 262 | patch = reshape(patch,numel(patch),1); 263 | 264 | maskTableRight = maskTable < 0; 265 | maskTableLeft = maskTable > 0; 266 | 267 | filtersRight = sum(bsxfun(@times, maskTableRight, patch)); 268 | filtersLeft = sum(bsxfun(@times, maskTableLeft, patch)); 269 | 270 | nRight = sum(maskTableRight); 271 | nLeft = sum(maskTableLeft); 272 | sqrRight = (sum(bsxfun(@times, maskTableRight, patch.^2))-sum(bsxfun(@times, maskTableRight, patch)).^2./nRight)./(nRight-1); 273 | sqrLeft = (sum(bsxfun(@times, maskTableLeft, patch.^2))-sum(bsxfun(@times, maskTableLeft, patch)).^2./nLeft)./(nLeft-1); 274 | 275 | 276 | obj.respMap(1:4,:) = [filtersRight; metaTable(1,:); filtersLeft; metaTable(2,:)]; 277 | obj.respMap(obj.C,:) = 0.5*obj.respMap(obj.Fr,:)./obj.respMap(obj.Lr,:)-0.5*obj.respMap(obj.Fl,:)./obj.respMap(obj.Ll,:); 278 | obj.respMap(obj.NORM,:) = metaTable(3,:); 279 | obj.respMap(obj.minC,:) = obj.respMap(obj.C,:); 280 | obj.respMap(obj.maxC,:) = obj.respMap(obj.C,:); 281 | 282 | if prm.radian 283 | myPi = pi; 284 | metaTable(4,:) = metaTable(4,:)*myPi/180; 285 | else 286 | myPi = 180; 287 | end 288 | 289 | obj.respMap(obj.thetaBegin,:) = mod(metaTable(4,:),2*myPi); 290 | obj.respMap(obj.thetaEnd,:) = mod(metaTable(4,:),2*myPi); 291 | %[m,n] = size(metaTable); 292 | coordsx = edgeIndx; 293 | coordsy = edgeIndy; 294 | coordsx = coordsx+obj.p1(1); 295 | coordsy = coordsy+obj.p1(2); 296 | obj.respPixels = sub2ind(size(Ior),coordsx,coordsy); 297 | 298 | prm = getPrm(obj.param); 299 | w = prm.filterWidth; 300 | %L = obj.respMap(obj.NORM,:); 301 | L = 0.5*(obj.respMap(obj.Lr,:)+obj.respMap(obj.Ll,:))./w; 302 | NL = obj.searchSpace(obj.level,obj.N,L,obj.param); 303 | T = obj.threshold(obj.sigma,2*w,L,NL,obj.param,obj.N); 304 | obj.respMap(obj.S,:) = abs(obj.respMap(obj.C,:))-T; 305 | 306 | if prm.eliminateEpsilons 307 | cont = obj.respMap(obj.C,:); 308 | epsilon = abs(cont) < obj.sigma*prm.eliminateEpsilonsFactor; 309 | obj.respMap(1:4,epsilon) = nan; 310 | end 311 | 312 | if prm.doVarTest 313 | alpha = prm.varTestAlpha; 314 | varTestRight = abs(sqrRight./obj.sigma^2-1) > sqrt(2/alpha)./sqrt(nRight-1) ; 315 | varTestLeft = abs(sqrLeft./obj.sigma^2-1) > sqrt(2/alpha)./sqrt(nLeft-1); 316 | 317 | obj.respMap(1:4,varTestRight & varTestLeft) = nan; 318 | end 319 | end 320 | 321 | function obj = markEdges(obj) 322 | prm = getPrm(obj.param); 323 | w = prm.filterWidth; 324 | L = min(obj.respMap(obj.Lr,:),obj.respMap(obj.Ll,:)); 325 | NL = obj.searchSpace(obj.level,obj.N,L); 326 | T = obj.threshold(obj.sigma,2*w,L,NL,obj.N); 327 | obj.respMap(obj.S,:) = abs(obj.respMap(obj.C,:))-T; 328 | 329 | isEdge = obj.respMap(obj.S,:)>0; 330 | obj.edgeMap = obj.respMap(:,isEdge); 331 | %obj.edgePixels = obj.respPixels(:,isEdge); 332 | 333 | posContrast = obj.edgeMap(obj.C,:) > 0; 334 | posTest = obj.edgeMap(obj.minC,:)>=0.5*obj.edgeMap(obj.C,:); 335 | negContrast = obj.edgeMap(obj.C,:) < 0; 336 | negTest = obj.edgeMap(obj.maxC,:)<=0.5*obj.edgeMap(obj.C,:); 337 | 338 | minConstTest = (posContrast & posTest) | (negContrast & negTest); 339 | obj.edgeMap(:,~minConstTest) = []; 340 | %obj.edgePixels(:,~minConstTest) = []; 341 | 342 | [Y,I1] = sort(obj.edgeMap(obj.NORM,:)); 343 | I1 = I1(end:-1:1); 344 | [Y,I2] = sort(obj.edgeMap(obj.S,I1)); 345 | I2 = I2(end:-1:1); 346 | obj.edgeMap = obj.edgeMap(:,I1); 347 | obj.edgeMap = obj.edgeMap(:,I2); 348 | %obj.edgePixels = obj.edgePixels(:,I1); 349 | %obj.edgePixels = obj.edgePixels(:,I2); 350 | end 351 | 352 | function orientation = getTriangleOrientation(obj) 353 | v = obj.edgeVecCell{1}; 354 | if v(1) == 1 && v(2) == 0 355 | orientation = 0; 356 | elseif v(1) == 0 && v(2) == 1 357 | orientation = 1; 358 | elseif v(1) == -1 && v(2) == 0 359 | orientation = 2; 360 | elseif v(1) == 0 && v(2) == -1 361 | orientation = 3; 362 | else 363 | orientation = -1; 364 | end 365 | end 366 | 367 | function obj = updateEdgeVectors(obj) 368 | obj.edgeVecCell = cell(1,3); 369 | obj.edgeVecStartCell = cell(1,3); 370 | vEdge0 = (obj.p2-obj.p1)/(obj.length-1); 371 | vEdge1 = (obj.p3-obj.p2)/(obj.length-1); 372 | vEdge2 = (obj.p1-obj.p3)/(obj.lengthHypo-1); 373 | obj.edgeVecCell{1} = vEdge0; 374 | obj.edgeVecCell{2} = vEdge1; 375 | obj.edgeVecCell{3} = vEdge2; 376 | obj.edgeVecStartCell{1} = obj.p1; 377 | obj.edgeVecStartCell{2} = obj.p2; 378 | obj.edgeVecStartCell{3} = obj.p3; 379 | end 380 | 381 | end 382 | 383 | methods (Static) 384 | function [respMapNew respPixelsNew]= updateRespMapPlusPlus(respMap,param,length,lengthHypo,blockSize,level,N,sigma) 385 | 386 | prm = getPrm(param); 387 | w = prm.filterWidth; 388 | fname = sprintf('Files/level%d_%d.mat',length,lengthHypo); 389 | 390 | load(fname); 391 | 392 | if prm.radian 393 | myPi = pi; 394 | else 395 | myPi = 180; 396 | end 397 | 398 | [m,n] = size(res); 399 | res(res == 0) = nan; 400 | curArr = res; 401 | signArr = sign(curArr); 402 | absArr = abs(curArr); 403 | absArr(2:2:end,:) = absArr(2:2:end,:)+blockSize; 404 | 405 | blocks = size(respMap,2)/blockSize/2; 406 | 407 | signArrNew = repmat(signArr,1,blocks); 408 | absArrNew = repmat(absArr,1,blocks); 409 | 410 | [rows,cols] = size(absArr); 411 | 412 | vec = 0:blocks-1; 413 | vec = ones(cols,1)*vec; 414 | vec = vec(:)'; 415 | vec = ones(rows,1)*vec; 416 | addInd = vec*2*blockSize; 417 | 418 | absArrNew = absArrNew+addInd; 419 | 420 | resNew = absArrNew.*signArrNew; 421 | 422 | 423 | [m,n] = size(resNew); 424 | curArr = resNew; 425 | signArr = signArrNew; 426 | absArr = absArrNew; 427 | absArrNoNan = absArr; 428 | absArrNoNan(isnan(absArrNoNan)) = 1; 429 | 430 | %% single edges 431 | isSingleLeft = isnan(curArr(2,:)); 432 | isSingleRight = isnan(curArr(1,:)); 433 | isSingle = isSingleLeft | isSingleRight; 434 | isRegular = ~isSingle; 435 | 436 | bestIndLeft = absArrNoNan(1,:); 437 | dataSingleLeft = respMap(:,bestIndLeft); 438 | %pixelsSingleLeft = respPixels(:,absArrNoNan(1,:)); 439 | 440 | notSingleLeft = ~isSingleLeft; 441 | dataSingleLeft(:,notSingleLeft) = 0; 442 | bestIndLeft(:,notSingleLeft) = 0; 443 | %pixelsSingleLeft(:,~isSingleLeft) = 0; 444 | 445 | bestIndRight = absArrNoNan(2,:); 446 | dataSingleRight = respMap(:,bestIndRight); 447 | %pixelsSingleRight = respPixels(:,absArrNoNan(2,:)); 448 | 449 | notSingleRight = ~isSingleRight; 450 | dataSingleRight(:,notSingleRight) = 0; 451 | bestIndRight(:,notSingleRight) = 0; 452 | %pixelsSingleRight(:,~isSingleRight) = 0; 453 | 454 | dataSingle = dataSingleRight+dataSingleLeft; 455 | %pixelsSingle = pixelsSingleRight+pixelsSingleLeft; 456 | 457 | bestInd = bestIndLeft+bestIndRight; 458 | 459 | dataSingle = [dataSingle(TrianglesTree.Fl,:); dataSingle(TrianglesTree.Ll,:); dataSingle(TrianglesTree.Fr,:); dataSingle(TrianglesTree.Lr,:); -dataSingle(TrianglesTree.C,:); -dataSingle(TrianglesTree.maxC,:); -dataSingle(TrianglesTree.minC,:); dataSingle(TrianglesTree.NORM,:);bestInd ; bestInd; mod(myPi+dataSingle(TrianglesTree.thetaEnd,:),2*myPi); mod(myPi+dataSingle(TrianglesTree.thetaBegin,:),2*myPi); dataSingle(TrianglesTree.turnSqr,:); dataSingle(TrianglesTree.turnNum,:);dataSingle(TrianglesTree.S,:)]; 460 | %pixelsSingle = [pixelsSingle ;zeros(size(pixelsSingle))]; 461 | 462 | dataSingle(:,isRegular) = 0; 463 | 464 | % regular edge 465 | absLeft = absArr(1:2:end,:); 466 | signLeft = signArr(1:2:end,:); 467 | signLeft = (signLeft == 1); 468 | absRight = absArr(2:2:end,:); 469 | signRight = signArr(2:2:end,:); 470 | signRight = (signRight == 1); 471 | 472 | % reading data into map 473 | absLeft(:,isSingle) = 1; 474 | absRight(:,isSingle) = 1; 475 | fll = respMap(TrianglesTree.Fl,:); 476 | fllMap = fll(absLeft); 477 | flr = respMap(TrianglesTree.Fr,:); 478 | flrMap = flr(absLeft); 479 | %frl = respMap(TrianglesTree.Fl,:); 480 | frlMap = fll(absRight); 481 | %frr = respMap(TrianglesTree.Fr,:); 482 | frrMap = flr(absRight); 483 | fllMap(:,isSingle) = 0; 484 | flrMap(:,isSingle) = 0; 485 | frlMap(:,isSingle) = 0; 486 | frrMap(:,isSingle) = 0; 487 | 488 | Lll = respMap(TrianglesTree.Ll,:); 489 | LllMap = Lll(absLeft); 490 | Llr = respMap(TrianglesTree.Lr,:); 491 | LlrMap = Llr(absLeft); 492 | %Lrl = respMap(TrianglesTree.Ll,:); 493 | LrlMap = Lll(absRight); 494 | %Lrr = respMap(TrianglesTree.Lr,:); 495 | LrrMap = Llr(absRight); 496 | LllMap(:,isSingle) = 0; 497 | LlrMap(:,isSingle) = 0; 498 | LrlMap(:,isSingle) = 0; 499 | LrrMap(:,isSingle) = 0; 500 | 501 | Tlb = respMap(TrianglesTree.thetaBegin,:); 502 | TlbMap = Tlb(absLeft); 503 | Tle = respMap(TrianglesTree.thetaEnd,:); 504 | TleMap = Tle(absLeft); 505 | %Lrb = respMap(TrianglesTree.Ll,:); 506 | TrbMap = Tlb(absRight); 507 | %Lrr = respMap(TrianglesTree.Lr,:); 508 | TreMap = Tle(absRight); 509 | TlbMap(:,isSingle) = 0; 510 | TleMap(:,isSingle) = 0; 511 | TrbMap(:,isSingle) = 0; 512 | TreMap(:,isSingle) = 0; 513 | 514 | Tsqr = respMap(TrianglesTree.turnSqr,:); 515 | TlsqrMap = Tsqr(absLeft); 516 | Tnum = respMap(TrianglesTree.turnNum,:); 517 | TlnumMap = Tnum(absLeft); 518 | TrsqrMap = Tsqr(absRight); 519 | TrnumMap = Tnum(absRight); 520 | 521 | Tsqrold = TlsqrMap+TrsqrMap; 522 | Tnumold = TlnumMap+TrnumMap; 523 | 524 | Tsqrold(:,isSingle) = 0; 525 | Tnumold(:,isSingle) = 0; 526 | 527 | % calculation new filters 528 | notSignLeft = ~signLeft; 529 | notSignRight = ~signRight; 530 | filterLeft = signLeft.*fllMap+notSignLeft.*flrMap+signRight.*frlMap+notSignRight.*frrMap; 531 | filterRight = signLeft.*flrMap+notSignLeft.*fllMap+signRight.*frrMap+notSignRight.*frlMap; 532 | 533 | lengthLeft = signLeft.*LllMap+notSignLeft.*LlrMap+signRight.*LrlMap+notSignRight.*LrrMap; 534 | lengthRight = signLeft.*LlrMap+notSignLeft.*LllMap+signRight.*LrrMap+notSignRight.*LrlMap; 535 | 536 | case1 = notSignLeft & signRight; 537 | case2 = notSignLeft & notSignRight; 538 | case3 = signLeft & notSignRight; 539 | 540 | thetaBeginAll = case1.*(myPi+TleMap)+case2.*(myPi+TleMap)+case3.*(myPi+TreMap); 541 | thetaSplit1 = case1.*(myPi+TlbMap)+case2.*(myPi+TlbMap)+case3.*(myPi+TrbMap); 542 | thetaEndAll = case1.*TreMap+case2.*(myPi+TrbMap)+case3.*TleMap; 543 | thetaSplit2 = case1.*TrbMap+case2.*(myPi+TreMap)+case3.*TlbMap; 544 | 545 | splitAng = mod(abs(thetaSplit1-thetaSplit2),2*myPi); 546 | isHighAng = splitAng>myPi; 547 | splitAng(isHighAng) = 2*myPi-splitAng(isHighAng); 548 | 549 | if prm.radian 550 | isHighAng = splitAng>(prm.highestTurnAngle*myPi/180); 551 | else 552 | isHighAng = splitAng>prm.highestTurnAngle; 553 | end 554 | %splitAng(isHighAng) = splitAng(isHighAng)-2*myPi; 555 | 556 | Tsqrnew = splitAng.^2+Tsqrold; 557 | Tnumnew = Tnumold+1; 558 | respShape = Tsqrnew./Tnumnew; 559 | 560 | if prm.radian 561 | sigmaShape = (prm.sigmaShape*myPi/180)^2; 562 | shapeWeight = prm.radianScoreWeight; 563 | else 564 | sigmaShape = prm.sigmaShape^2; 565 | shapeWeight = prm.shapeScoreWeight; 566 | end 567 | 568 | 569 | %% continute turns code from here 570 | 571 | edgeLength = 0.5*(lengthLeft+lengthRight)./w; 572 | %edgeLength = 2^(level-1); 573 | resp = 0.5*filterRight./lengthRight-0.5*filterLeft./lengthLeft; 574 | NL = TrianglesTree.searchSpace(level,N,edgeLength,param); 575 | T = TrianglesTree.threshold(sigma,2*w,edgeLength,NL,param,N); 576 | 577 | %Tshape = sigmaShape*(2*log(2*myPi)-log(2*pi*sigmaShape)-2*log(NL)./Tnumnew); 578 | Tshape = sigmaShape*(2*log(1*myPi)-log(2*pi*sigmaShape)); 579 | contrastScore = abs(resp)-T; 580 | shapeScore = sqrt(Tshape)-sqrt(respShape); 581 | shapeScore(Tnumnew == 0) = 0; 582 | 583 | %score = shapeWeight*shapeScore+(1-shapeWeight)*contrastScore; 584 | score = (1-shapeWeight)*contrastScore+shapeWeight*shapeScore; 585 | score(isHighAng) = nan; 586 | [maxScore,maxInd] = max(score,[],1); 587 | nanScore = isnan(maxScore); 588 | %a(0) = 1; 589 | indices = sub2ind(size(absLeft),maxInd,1:n); 590 | 591 | bestContrastScore = contrastScore(indices); 592 | posContrastScore = bestContrastScore>0; 593 | 594 | bestThetaBegin = mod(thetaBeginAll(indices),2*myPi); 595 | bestThetaEnd = mod(thetaEndAll(indices),2*myPi); 596 | bestTsqr = Tsqrnew(indices); 597 | bestTnum = Tnumnew(indices); 598 | 599 | bestAbsLeft = absLeft(indices); 600 | bestSignLeft = signLeft(indices); 601 | bestAbsRight = absRight(indices); 602 | bestSignRight = signRight(indices); 603 | 604 | maxResp = resp(indices); 605 | maxFilterLeft = filterLeft(indices); 606 | maxFilterRight = filterRight(indices); 607 | maxLengthLeft = lengthLeft(indices); 608 | maxLengthRight = lengthRight(indices); 609 | 610 | bestMinLeft = respMap(TrianglesTree.minC,bestAbsLeft); 611 | bestMaxLeft = respMap(TrianglesTree.maxC,bestAbsLeft); 612 | bestMinRight = respMap(TrianglesTree.minC,bestAbsRight); 613 | bestMaxRight = respMap(TrianglesTree.maxC,bestAbsRight); 614 | bestNormLeft = respMap(TrianglesTree.NORM,bestAbsLeft); 615 | bestNormRight = respMap(TrianglesTree.NORM,bestAbsRight); 616 | 617 | 618 | notBestSignLeft = ~bestSignLeft; 619 | notBestSignRight = ~bestSignRight; 620 | minLeft = bestSignLeft.*bestMinLeft+notBestSignLeft.*(-bestMaxLeft); 621 | maxLeft = bestSignLeft.*bestMaxLeft+notBestSignLeft.*(-bestMinLeft); 622 | minRight = bestSignRight.*bestMinRight+notBestSignRight.*(-bestMaxRight); 623 | maxRight = bestSignRight.*bestMaxRight+notBestSignRight.*(-bestMinRight); 624 | 625 | norm = bestNormLeft+bestNormRight; 626 | 627 | highNorm = norm>prm.minContrast; 628 | 629 | notHighNorm = ~highNorm; 630 | minContrast = highNorm.*min(minRight,minLeft)+notHighNorm.*maxResp; 631 | maxContrast = highNorm.*max(maxRight,maxLeft)+notHighNorm.*maxResp; 632 | 633 | dataRegular = [maxFilterRight;maxLengthRight;maxFilterLeft;maxLengthLeft;maxResp;minContrast;maxContrast;norm;bestAbsLeft;bestAbsRight;bestThetaBegin;bestThetaEnd;bestTsqr;bestTnum;maxScore.*posContrastScore]; 634 | %pixelsRegular = [bestPixelsLeft;bestPixelsRight]; 635 | dataRegular(:,nanScore & isRegular) = nan; 636 | dataRegular(:,isSingle) = 0; 637 | %pixelsRegular(:,nanScore) = 0; 638 | respMapNew = dataRegular+dataSingle; 639 | respPixelsNew = 0;%pixelsRegular+pixelsSingle; 640 | end 641 | 642 | function ind = getIndexFromEdge(edgeNumber1,vertexNumber1,edgeNumber2,vertexNumber2,edgeSize,hypoSize) 643 | subIndEdge = vertexNumber1*edgeSize+vertexNumber2; 644 | subIndHypo = vertexNumber1*hypoSize+vertexNumber2; 645 | if edgeNumber1 == 0 && edgeNumber2 == 1 646 | ind = subIndEdge; 647 | elseif edgeNumber1 == 0 && edgeNumber2 == 2 648 | ind = edgeSize^2+subIndHypo; 649 | elseif edgeNumber1 == 1 && edgeNumber2 == 2 650 | ind = (edgeSize^2)+edgeSize*hypoSize+subIndHypo; 651 | end 652 | ind = ind+1; 653 | end 654 | 655 | % todo support hypotenus size 656 | function [x,y] = getXYfromIndex(edgeNumber,vertexNumber,edgeSize) 657 | x = 0; 658 | y = 0; 659 | if edgeNumber == 0 660 | x = x+vertexNumber; 661 | elseif edgeNumber == 1 662 | x = x+edgeSize-1; 663 | y = y+vertexNumber; 664 | elseif edgeNumber == 2 665 | x = x+edgeSize-1-vertexNumber; 666 | y = y+edgeSize-1-vertexNumber; 667 | else 668 | x = -1; 669 | y = -1; 670 | end 671 | end 672 | 673 | function NL = searchSpace(level,N,L,param) 674 | prm = getPrm(param); 675 | j = level-1; 676 | if prm.newSearchSpace 677 | %NL = exp(L/3); 678 | %NL = prm.searchSpaceFact*N*(2^(0.5*j)); 679 | %NL = prm.searchSpaceFact*N*(2^(0.5*j)); 680 | else 681 | NL = prm.searchSpaceFact*N; 682 | end 683 | end 684 | 685 | function T = threshold(sigma,w,L,NL,param,N) 686 | prm = getPrm(param); 687 | if prm.newThreshold 688 | T = sigma.*sqrt(log(NL.*w.*L)./(w.*L)); 689 | %T = sigma.*sqrt(2*log(6*N)./(w.*L)+2/(3*w)); 690 | %T = sigma.*sqrt(log(6*N*w*L)./(w.*L)+2/(3*w)); 691 | else 692 | T = sigma.*sqrt(2.*log(NL)./(w.*L)+prm.expConst); 693 | end 694 | end 695 | end 696 | 697 | end -------------------------------------------------------------------------------- /createPatchMasks.m: -------------------------------------------------------------------------------- 1 | function createPatchMasksOld(param) 2 | index = 1; 3 | prm = getPrm(param); 4 | S = prm.minLength; 5 | w = prm.filterWidth; 6 | 7 | numOfEdges = (2+1)*S^2; 8 | maskTableL0 = zeros((S+2*w)^2,numOfEdges); 9 | maskTableL1 = zeros((S+2*w)^2,numOfEdges); 10 | maskTableL2 = zeros((S+2*w)^2,numOfEdges); 11 | maskTableL3 = zeros((S+2*w)^2,numOfEdges); 12 | 13 | edgeTableL0 = zeros((S)^2,numOfEdges); 14 | edgeTableL1 = zeros((S)^2,numOfEdges); 15 | edgeTableL2 = zeros((S)^2,numOfEdges); 16 | edgeTableL3 = zeros((S)^2,numOfEdges); 17 | 18 | edgeIndx = zeros(S,numOfEdges)+NaN; 19 | edgeIndxL1 = zeros(S,numOfEdges)+NaN; 20 | edgeIndxL2 = zeros(S,numOfEdges)+NaN; 21 | edgeIndxL3 = zeros(S,numOfEdges)+NaN; 22 | edgeIndy = zeros(S,numOfEdges)+NaN; 23 | edgeIndyL1 = zeros(S,numOfEdges)+NaN; 24 | edgeIndyL2 = zeros(S,numOfEdges)+NaN; 25 | edgeIndyL3 = zeros(S,numOfEdges)+NaN; 26 | 27 | metaSize = 8; 28 | metaTableL0 = zeros(metaSize,numOfEdges); 29 | metaTableL1 = zeros(metaSize,numOfEdges); 30 | metaTableL2 = zeros(metaSize,numOfEdges); 31 | metaTableL3 = zeros(metaSize,numOfEdges); 32 | gap = w+1; 33 | 34 | for edge1 = 0:1 35 | for edge2 = edge1+1:2 36 | inTriangle = getInTriangle(edge1,edge2,S,w); 37 | for v1 = 0:S-1 38 | for v2 = 0:S-1 39 | [x0,y0] = TrianglesTree.getXYfromIndex(edge1,v1,S); 40 | [x1,y1] = TrianglesTree.getXYfromIndex(edge2,v2,S); 41 | ind = TrianglesTree.getIndexFromEdge(edge1,v1,edge2,v2,S,S); 42 | L = max(abs(x1-x0),abs(y1-y0)); 43 | v = [x1-x0,y1-y0]; 44 | length = norm(v); 45 | theta = atan(v(2)/v(1)); 46 | 47 | theta = 180*theta/pi; 48 | 49 | if v(1)<0 50 | theta = theta+180; 51 | elseif theta<0 52 | theta = theta+360; 53 | end 54 | if L == 0 55 | continue; 56 | end 57 | 58 | line = Line(x0+gap,y0+gap,x1+gap,y1+gap,w*2); 59 | curMask = line.getEdgeFilter(S+2*w,S+2*w); 60 | 61 | left = curMask>0; 62 | right = curMask<0; 63 | %left = left & inTriangle; 64 | %right = right & inTriangle; 65 | 66 | Lr = sum(right(:)); 67 | Ll = sum(left(:)); 68 | 69 | if Lr == 0 70 | Lr = nan; 71 | end 72 | if Ll == 0 73 | Ll = nan; 74 | end 75 | 76 | curMask = left-right; 77 | 78 | if isnan(Lr) || isnan(Ll) 79 | curMask = zeros(S+2*w); 80 | else 81 | subplot(10,10,index),imshow(curMask/2+0.5); 82 | index = index+1; 83 | end 84 | 85 | curMaskL1 = imrotate(curMask,90); 86 | curMaskL2 = imrotate(curMask,180); 87 | curMaskL3 = imrotate(curMask,270); 88 | curMask = reshape(curMask,(S+2*w)^2,1); 89 | curMaskL1 = reshape(curMaskL1,(S+2*w)^2,1); 90 | curMaskL2 = reshape(curMaskL2,(S+2*w)^2,1); 91 | curMaskL3 = reshape(curMaskL3,(S+2*w)^2,1); 92 | 93 | line1 = Line(x0+1,y0+1,x1+1,y1+1,1); 94 | curEdge = line1.getLineImage(S,S); 95 | 96 | curEdgeL1 = imrotate(curEdge,90); 97 | curEdgeL2 = imrotate(curEdge,180); 98 | curEdgeL3 = imrotate(curEdge,270); 99 | 100 | [indx,indy] = find(curEdge); 101 | indx = indx-1; 102 | indy = indy-1; 103 | %[indyL1,indxL1] = find(curEdgeL1); 104 | indxL1 = -indy; 105 | indyL1 = indx; 106 | %[indxL2,indyL2] = find(curEdgeL2); 107 | indxL2 = -indx; 108 | indyL2 = -indy; 109 | %[indyL3,indxL3] = find(curEdgeL3); 110 | indxL3 = indy; 111 | indyL3 = -indx; 112 | 113 | curEdge = reshape(curEdge,(S)^2,1); 114 | curEdgeL1 = reshape(curEdgeL1,(S)^2,1); 115 | curEdgeL2 = reshape(curEdgeL2,(S)^2,1); 116 | curEdgeL3 = reshape(curEdgeL3,(S)^2,1); 117 | 118 | maskTableL0(:,ind) = curMask(:); 119 | maskTableL1(:,ind) = curMaskL1(:); 120 | maskTableL2(:,ind) = curMaskL2(:); 121 | maskTableL3(:,ind) = curMaskL3(:); 122 | 123 | edgeTableL0(:,ind) = curEdge(:); 124 | edgeTableL1(:,ind) = curEdgeL1(:); 125 | edgeTableL2(:,ind) = curEdgeL2(:); 126 | edgeTableL3(:,ind) = curEdgeL3(:); 127 | 128 | edgeIndx(1:numel(indx),ind) = indx(:); 129 | edgeIndxL1(1:numel(indxL1),ind) = indxL1(:); 130 | edgeIndxL2(1:numel(indxL2),ind) = indxL2(:); 131 | edgeIndxL3(1:numel(indxL3),ind) = indxL3(:); 132 | 133 | edgeIndy(1:numel(indy),ind) = indy(:); 134 | edgeIndyL1(1:numel(indyL1),ind) = indyL1(:); 135 | edgeIndyL2(1:numel(indyL2),ind) = indyL2(:); 136 | edgeIndyL3(1:numel(indyL3),ind) = indyL3(:); 137 | 138 | metaTableL0(:,ind) = [Lr Ll length theta x0 y0 x1 y1]'; 139 | metaTableL1(:,ind) = [Lr Ll length theta+90 -y0 x0 -y1 x1]'; 140 | metaTableL2(:,ind) = [Lr Ll length theta+180 -x0 -y0 -x1 -y1]'; 141 | metaTableL3(:,ind) = [Lr Ll length theta+270 y0 -x0 y1 -x1]'; 142 | end 143 | end 144 | end 145 | end 146 | 147 | l0.maskTable = maskTableL0; 148 | l0.metaTable = metaTableL0; 149 | l0.edgeTable = edgeTableL0; 150 | l0.edgeIndx = edgeIndx; 151 | l0.edgeIndy = edgeIndy; 152 | 153 | l1.maskTable = maskTableL1; 154 | l1.metaTable = metaTableL1; 155 | l1.edgeTable = edgeTableL1; 156 | l1.edgeIndx = edgeIndxL1; 157 | l1.edgeIndy = edgeIndyL1; 158 | 159 | l2.maskTable = maskTableL2; 160 | l2.metaTable = metaTableL2; 161 | l2.edgeTable = edgeTableL2; 162 | l2.edgeIndx = edgeIndxL2; 163 | l2.edgeIndy = edgeIndyL2; 164 | 165 | l3.maskTable = maskTableL3; 166 | l3.metaTable = metaTableL3; 167 | l3.edgeTable = edgeTableL3; 168 | l3.edgeIndx = edgeIndxL3; 169 | l3.edgeIndy = edgeIndyL3; 170 | 171 | cd Files; 172 | save('l0.mat', '-struct', 'l0'); 173 | save('l1.mat', '-struct', 'l1'); 174 | save('l2.mat', '-struct', 'l2'); 175 | save('l3.mat', '-struct', 'l3'); 176 | cd ..; 177 | end 178 | 179 | function inTriangle = getInTriangle(edge1,edge2,S,w) 180 | L = S+2*w; 181 | inTriangle = zeros(L); 182 | 183 | for i = 1:L 184 | for j = 1:L 185 | if edge1 == 0 && edge2 == 1 && j>=w+1 && i<=L-w 186 | inTriangle(i,j) = 1; 187 | elseif edge1 == 0 && edge2 == 2 && i>=j && j>=w+1 188 | inTriangle(i,j) = 1; 189 | elseif edge1 == 1 && edge2 == 2 && i>=j && i<=L-w 190 | inTriangle(i,j) = 1; 191 | end 192 | end 193 | end 194 | end -------------------------------------------------------------------------------- /getPrm.m: -------------------------------------------------------------------------------- 1 | function prm = getPrm(ind) 2 | prm.filterWidth = 2; 3 | prm.doMinContrastTest = true; 4 | prm.minContrast = 8; 5 | prm.minLength = 5; 6 | prm.nmsThres = 0.5; 7 | prm.eliminateEpsilons = true; 8 | prm.eliminateEpsilonsFactor = 0.225; 9 | prm.varTestAlpha = 0.1; 10 | prm.eliminateShortEdges = true; 11 | prm.nmsWindow = 3; 12 | prm.highestTurnAngle = 48; 13 | prm.radian = true; 14 | prm.shapeScoreWeight = 0.001;%0.0542;%0.001; 15 | prm.radianScoreWeight = 0.0545; 16 | prm.sigmaShape = 30; 17 | prm.addShift = true; 18 | prm.normalizeScore = false; 19 | prm.newThreshold = false; 20 | prm.newSearchSpace = false; 21 | prm.searchSpaceFact = 7; 22 | prm.doVarTest = true; 23 | prm.maxParam = 0; 24 | prm.jLevel = 3; 25 | prm.tFact = 1; 26 | prm.block = 129; 27 | prm.gap = 10; 28 | prm.padWithNan = false; 29 | prm.sigma = 0.1; 30 | prm.doNMS = true; 31 | prm.expConst = 0; 32 | end 33 | 34 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | clear; clc; close all; 2 | 3 | param = 0; 4 | 5 | disp('Creating Masks'); 6 | tic; 7 | if ~exist('Files/l0.mat', 'file') 8 | createPatchMasks(param); 9 | end 10 | 11 | disp('Building Tree'); 12 | 13 | dirInfo = dir('Images/'); 14 | 15 | disp('PNG files in the directory:'); 16 | for i = 1:length(dirInfo) 17 | if ~dirInfo(i).isdir && endsWith(dirInfo(i).name, '.png', 'IgnoreCase', true) 18 | fprintf('%d) %s\n', i-2, dirInfo(i).name); 19 | end 20 | end 21 | 22 | menu = input("select image: "); 23 | switch num2str(menu) 24 | case "1" 25 | I = im2double(imread('Images/CC.png')); 26 | case "2" 27 | I = im2double(imread('Images/Sines.png')); 28 | case "3" 29 | I = im2double(imread('Images/Sqr.png')); 30 | end 31 | 32 | 33 | fastRun = false; 34 | if fastRun 35 | I = imresize(I,[65 65]); 36 | end 37 | 38 | sigma = 0.1; 39 | [res,im] = runIm(I,false,param); 40 | disp('Displaying Edges'); 41 | figure; 42 | subplot(1,2,1);imshow(res); 43 | subplot(1,2,2);imshow(I); 44 | toc; -------------------------------------------------------------------------------- /nonMaximalSupression.m: -------------------------------------------------------------------------------- 1 | function resI = nonMaximalSupression(pixels,edgeValues,edgePriority,imSize,coorThresh,nmsHolder) 2 | resI = nmsHolder; 3 | selected = nmsHolder>0; 4 | 5 | [edgePriority,I] = sort(edgePriority); 6 | pixels = pixels(:,I); 7 | edgeValues = edgeValues(1,I); 8 | 9 | lastPriority = 1; 10 | edgePixels = []; 11 | [m,n] = size(pixels); 12 | edgeCounter = 0; 13 | for i=1:n 14 | curPriority = edgePriority(i); 15 | if curPriority > lastPriority 16 | curEdge = zeros(imSize); 17 | edgePixels(isnan(edgePixels) | edgePixels == 0) = []; 18 | curEdge(edgePixels) = true; 19 | L = sum(curEdge(:)); 20 | %curEdge = imclose(curEdge, true(5)); 21 | curEdgeWide = imdilate(curEdge, true(3)); 22 | 23 | coorIm = curEdgeWide & selected; 24 | coor = sum(coorIm(:))/L; 25 | 26 | if coor5 27 | selected = selected | curEdgeWide; 28 | %figure,imshow(curEdge); 29 | curEdge = curEdge*edgeValues(i-1); 30 | resI = max(resI,curEdge); 31 | edgeCounter = edgeCounter+1; 32 | end 33 | edgePixels = pixels(:,i); 34 | lastPriority = curPriority; 35 | else 36 | edgePixels = [edgePixels;pixels(:,i)]; 37 | end 38 | end 39 | 40 | fprintf('Final Num of Edges = %d\n', edgeCounter); 41 | end -------------------------------------------------------------------------------- /nonMaximalSupressionPlusPlus.m: -------------------------------------------------------------------------------- 1 | function resI = nonMaximalSupressionPlusPlus(edgesIndices,edgesScores,pixels,imSize,coorThresh) 2 | 3 | resI = zeros(imSize); 4 | selected = false(imSize); 5 | 6 | edgeCounter = 0; 7 | [m,n] = size(edgesIndices); 8 | 9 | for i=1:n 10 | curIndices = edgesIndices(:,i); 11 | curIndices(curIndices == 0 | isnan(curIndices)) = []; 12 | curPixels = pixels(:,curIndices); 13 | curPixels = curPixels(:); 14 | curPixels(curPixels == 0 | isnan(curPixels)) = []; 15 | curI = false(imSize); 16 | curI(curPixels) = true; 17 | curIdialate = curI | [zeros(1,imSize(2)) ; curI(1:end-1,1:end)]|[curI(2:end,1:end);zeros(1,imSize(2))]|[curI(1:end,2:end) zeros(imSize(1),1)]|[zeros(imSize(1),1) curI(1:end,1:end-1)]; 18 | L = sum(curI(:)); 19 | 20 | coor = curIdialate & selected; 21 | 22 | if sum(coor(:))/L < coorThresh 23 | %figure,imshow(curI); 24 | edgeCounter = edgeCounter+1; 25 | selected = selected | curIdialate; 26 | resI = max(resI,curI*edgesScores(i)); 27 | end 28 | end 29 | 30 | fprintf('Final Num of Edges = %d\n', edgeCounter); 31 | end -------------------------------------------------------------------------------- /pouriya nourizadeh: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pouriya nuriadeh pp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdieslaminet/Image_Edge_Detection/6bc7f35caaf4beb8437dd50713058c60c2d4f71d/pouriya nuriadeh pp.pdf -------------------------------------------------------------------------------- /pouriya nuriadeh.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mahdieslaminet/Image_Edge_Detection/6bc7f35caaf4beb8437dd50713058c60c2d4f71d/pouriya nuriadeh.docx -------------------------------------------------------------------------------- /runFastIm.m: -------------------------------------------------------------------------------- 1 | function res = runFastIm(I,param) 2 | prm = getPrm(param); 3 | close all; 4 | addpath('/net/mraid11/export/data/yehonato/app2/SGE'); 5 | 6 | while 1 7 | folderName = sprintf('tmp%s', datestr(clock)); 8 | if ~exist(folderName,'dir') 9 | mkdir(folderName); 10 | break; 11 | end 12 | end 13 | 14 | sigma = prm.sigma; 15 | [m,n] = size(I); 16 | R = zeros(size(I)); 17 | block = prm.block; 18 | gap = prm.gap; 19 | 20 | xGrid = getGrid(block,gap,m); 21 | yGrid = getGrid(block,gap,n); 22 | 23 | if prm.addShift 24 | xShift = xGrid+2; 25 | yShift = yGrid+2; 26 | 27 | xShift(end) = xShift(end)-4; 28 | yShift(end) = yShift(end)-4; 29 | 30 | xGrid = [xGrid xShift]; 31 | yGrid = [yGrid yShift]; 32 | end 33 | 34 | iter = length(xGrid)*length(yGrid); 35 | 36 | data = cell(1,iter); 37 | curInd = 0; 38 | 39 | for x0 = xGrid 40 | for y0 = yGrid 41 | curInd = curInd+1; 42 | curI = I(x0:x0+block-1,y0:y0+block-1); 43 | s.x = x0; 44 | s.y = y0; 45 | data{curInd} = s; 46 | 47 | img.I = curI; 48 | 49 | save(sprintf('%s/%d.mat',folderName,curInd),'-struct','img'); 50 | end 51 | end 52 | 53 | code = sprintf('cd /net/mraid11/export/data/yehonato/app2; runImFromMat(''%s'', index,%d)',folderName,param); 54 | 55 | code; 56 | 57 | run_parallel(code, 'index', num2cell(1:iter),'-cluster', 'mcluster01'); 58 | 59 | for i=1:iter 60 | load(sprintf('%s/%dres.mat',folderName,i)); 61 | x0 = data{i}.x; 62 | y0 = data{i}.y; 63 | R(x0:x0+block-1,y0:y0+block-1) = max(R(x0:x0+block-1,y0:y0+block-1),curR); 64 | end 65 | res = R; 66 | 67 | rmdir(folderName,'s'); 68 | end 69 | 70 | function grid = getGrid(block,gap,max) 71 | grid = zeros(1,max); 72 | grid(1) = 1; 73 | for i= 2:max 74 | grid(i)= grid(i-1)+block-gap; 75 | if grid(i)+block-1>max 76 | grid(i) = max-block+1; 77 | break; 78 | end 79 | end 80 | grid(grid == 0) = []; 81 | 82 | if length(grid)>=2 && grid(end) == grid(end-1) 83 | grid(end) = []; 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /runIm.m: -------------------------------------------------------------------------------- 1 | function [res,im] = runIm(I,addShift,param) 2 | close all; 3 | 4 | prm = getPrm(param); 5 | sigma = prm.sigma; 6 | 7 | tic; 8 | im = Image(I,param,sigma); 9 | im = im.buildTree(true); 10 | if prm.doNMS 11 | im = im.detectEdgesPlusPlus(); 12 | end 13 | R = im.resIgray; 14 | 15 | 16 | 17 | if addShift 18 | Inew = zeros(size(I)); 19 | Is = I(3:end,3:end); 20 | Inew(1:end-2,1:end-2) = Is; 21 | Inew(end-1:end,1:end) = I(1:2,1:end); 22 | Inew(1:end,end-1:end) = I(1:end,1:2); 23 | 24 | %Rnew = zeros(size(I)); 25 | %Rs = R(3:end,3:end); 26 | %Rnew(1:end-2,1:end-2) = Rs; 27 | %Rnew(end-1:end,1:end) = R(1:2,1:end); 28 | %Rnew(1:end,end-1:end) = R(1:end,1:2); 29 | 30 | 31 | if max(Inew(:))>1 32 | Inew = Inew./255; 33 | end 34 | 35 | %if max(Rnew(:))>1 36 | % Rnew = Rnew./255; 37 | %end 38 | 39 | im = Image(Inew,param,sigma); 40 | im = im.buildTree(true); 41 | 42 | if prm.doNMS 43 | im = im.detectEdgesPlusPlus(); 44 | end 45 | ShiftedRnew = im.resIgray; 46 | Rnew = zeros(size(I)); 47 | Rnew(3:end,3:end) = ShiftedRnew(1:end-2,1:end-2); 48 | 49 | R = max(R,Rnew); 50 | end 51 | R = R./max(R(:)); 52 | res = R; 53 | toc; 54 | %imshow(res); 55 | end 56 | -------------------------------------------------------------------------------- /runRealIm.m: -------------------------------------------------------------------------------- 1 | function res = runRealIm(I,param) 2 | prm = getPrm(param); 3 | close all; 4 | addShift = prm.addShift; 5 | 6 | tic; 7 | [m,n] = size(I); 8 | R = zeros(size(I)); 9 | block = prm.block; 10 | gap = prm.gap; 11 | 12 | xGrid = getGrid(block,gap,m); 13 | yGrid = getGrid(block,gap,n); 14 | 15 | iter = length(xGrid)*length(yGrid); 16 | 17 | iter 18 | 19 | for x0 = xGrid 20 | for y0 = yGrid 21 | curI = I(x0:x0+block-1,y0:y0+block-1); 22 | 23 | %im = Image(curI,param,sigma); 24 | %im = im.buildTree(true); 25 | %im = im.detectEdgesPlusPlus(); 26 | %curR = im.resIgray; 27 | [curR,im] = runIm(curI,addShift,param); 28 | 29 | curR(1:2,:) = 0; 30 | curR(end-1:end,:) = 0; 31 | curR(:,1:2) = 0; 32 | curR(:,end-1:end) = 0; 33 | 34 | R(x0:x0+block-1,y0:y0+block-1) = max(R(x0:x0+block-1,y0:y0+block-1),curR); 35 | end 36 | end 37 | 38 | res = R; 39 | end 40 | 41 | function grid = getGrid(block,gap,max) 42 | grid = zeros(1,max); 43 | grid(1) = 1; 44 | for i= 2:max 45 | grid(i)= grid(i-1)+block-gap; 46 | if grid(i)+block-1>max 47 | grid(i) = max-block+1; 48 | break; 49 | end 50 | end 51 | grid(grid == 0) = []; 52 | 53 | if length(grid)>=2 && grid(end) == grid(end-1) 54 | grid(end) = []; 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /updateRespMapFunc.m: -------------------------------------------------------------------------------- 1 | function [ respMap,respPixels ] = updateRespMapFunc(res,leftMap,leftPixels,rightMap,rightPixels,respMap,respPixels,sigma,N,level,w,Fl,Ll,Fr,Lr,C,minC,maxC,NORM,S) 2 | [m,n] = size(res); 3 | for ind = 1:n 4 | curArr = res(:,ind)'; 5 | curArr(curArr == 0) = []; 6 | signArr = sign(curArr); 7 | absArr = abs(curArr); 8 | 9 | if numel(curArr) == 2 10 | if isnan(curArr(2)) 11 | data = leftMap(:,absArr(1)); 12 | pixels = leftPixels(:,absArr(1)); 13 | else 14 | data = rightMap(:,absArr(2)); 15 | pixels = rightPixels(:,absArr(2)); 16 | end 17 | 18 | data = [data( Fl) data( Ll) data( Fr) data( Lr) -data( C) -data( maxC) -data( minC) data( NORM) data( S)]'; 19 | 20 | respMap(:,ind) = data; 21 | respPixels(:,ind) = [pixels ;zeros(size(pixels))+NaN]; 22 | else 23 | absLeft = absArr(1:2:end); 24 | signLeft = signArr(1:2:end); 25 | absRight = absArr(2:2:end); 26 | signRight = signArr(2:2:end); 27 | 28 | dataLeft = leftMap(:,absLeft); 29 | pixelLeft = leftPixels(:,absLeft); 30 | dataRight = rightMap(:,absRight); 31 | pixelRight = rightPixels(:,absRight); 32 | 33 | lenGap = 0; 34 | if signLeft(1)>0 35 | filterLeft = dataLeft( Fl,:); 36 | lengthLeft = dataLeft( Ll,:); 37 | filterRight = dataLeft( Fr,:); 38 | lengthRight = dataLeft( Lr,:); 39 | else 40 | filterLeft = dataLeft( Fr,:); 41 | lengthLeft = dataLeft( Lr,:); 42 | filterRight = dataLeft( Fl,:); 43 | lengthRight = dataLeft( Ll,:); 44 | end 45 | 46 | if signRight(1)>0 47 | filterLeft = filterLeft+dataRight( Fl,:); 48 | lengthLeft = lengthLeft+dataRight( Ll,:); 49 | filterRight = filterRight+dataRight( Fr,:); 50 | lengthRight = lengthRight+dataRight( Lr,:); 51 | else 52 | filterLeft = filterLeft+dataRight( Fr,:); 53 | lengthLeft = lengthLeft+dataRight( Lr,:); 54 | filterRight = filterRight+dataRight( Fl,:); 55 | lengthRight = lengthRight+dataRight( Ll,:); 56 | end 57 | lengthLeft = lengthLeft-lenGap; 58 | lengthRight = lengthRight-lenGap; 59 | 60 | 61 | minLength = min(lengthLeft,lengthRight); 62 | resp = 0.5*filterRight./lengthRight-0.5*filterLeft./lengthLeft; 63 | 64 | NL = 8*N*2^(0.25*level^2+0.25*level-0.5); 65 | T = 2.*sigma^2.*log(NL)./(w.*minLength); 66 | T = sqrt(T); 67 | score = abs(resp)-T; 68 | maxScore = max(score); 69 | bestInd = find(score == maxScore,1); 70 | 71 | 72 | if isempty(bestInd) 73 | respMap(:,ind) = zeros( S,1)+nan; 74 | else 75 | bestInd = bestInd(1); 76 | maxResp = resp(bestInd); 77 | 78 | respMap(1:5,ind) = [filterRight(bestInd);lengthRight(bestInd);filterLeft(bestInd);lengthLeft(bestInd);resp(bestInd)]; 79 | 80 | if signLeft(1) > 0 81 | minLeft = dataLeft( minC,bestInd); 82 | maxLeft = dataLeft( maxC,bestInd); 83 | else 84 | maxLeft = -dataLeft( minC,bestInd); 85 | minLeft = -dataLeft( maxC,bestInd); 86 | end 87 | if signRight(1) > 0 88 | minRight = dataRight( minC,bestInd); 89 | maxRight = dataRight( maxC,bestInd); 90 | else 91 | maxRight = -dataRight( minC,bestInd); 92 | minRight = -dataRight( maxC,bestInd); 93 | end 94 | 95 | respMap( NORM,ind) = dataLeft( NORM,bestInd)+dataRight( NORM,bestInd); 96 | 97 | if respMap( NORM,ind) > 4 98 | respMap( minC,ind) = min(minLeft,minRight); 99 | respMap( maxC,ind) = max(maxLeft,maxRight); 100 | else 101 | respMap( minC,ind) = maxResp; 102 | respMap( maxC,ind) = maxResp; 103 | end 104 | 105 | 106 | respPixels(:,ind) = [pixelLeft(:,bestInd) ;pixelRight(:,bestInd)]; 107 | end 108 | end 109 | end 110 | end --------------------------------------------------------------------------------