1 module des.il.func; 2 3 import std.algorithm; 4 import std.traits; 5 import std.range; 6 7 import des.il.util; 8 import des.il.image; 9 import des.il.region; 10 11 import des.ts; 12 13 import des.math.linear.vector; 14 15 import std.c.string : memcpy, memset; 16 17 /// 18 enum ImRepack 19 { 20 NONE, /// 21 ROT90, /// 22 ROT180,/// 23 ROT270,/// 24 MIRHOR,/// 25 MIRVER,/// 26 MTRANS,/// 27 STRANS,/// 28 } 29 30 private CrdVector!N permutateComp(size_t N,T)( in Vector!(N,T) v, ImRepack tr, size_t[2] crdNum ) pure 31 if( isIntegral!T ) 32 in 33 { 34 assert( crdNum[0] < v.length ); 35 assert( crdNum[1] < v.length ); 36 } 37 body 38 { 39 switch( tr ) 40 { 41 case ImRepack.ROT90: 42 case ImRepack.ROT270: 43 case ImRepack.MTRANS: 44 case ImRepack.STRANS: 45 auto ret = CrdVector!N(v); 46 ret[crdNum[0]] = v[crdNum[1]]; 47 ret[crdNum[1]] = v[crdNum[0]]; 48 return ret; 49 default: return CrdVector!N(v); 50 } 51 } 52 53 private void function( coord_t, coord_t, coord_t, coord_t, 54 ref coord_t, ref coord_t ) getRepackCrdFunc( ImRepack repack ) 55 out(fnc) { assert( fnc !is null ); } body 56 { 57 final switch( repack ) 58 { 59 case ImRepack.NONE: return &noRepackCrd; 60 case ImRepack.ROT90: return &rotCrd90; 61 case ImRepack.ROT180: return &rotCrd180; 62 case ImRepack.ROT270: return &rotCrd270; 63 case ImRepack.MIRHOR: return &mirHorCrd; 64 case ImRepack.MIRVER: return &mirVerCrd; 65 case ImRepack.MTRANS: return &mTransCrd; 66 case ImRepack.STRANS: return &sTransCrd; 67 } 68 } 69 70 private 71 { 72 void noRepackCrd( coord_t px, coord_t py, coord_t sx, coord_t sy, 73 ref coord_t rx, ref coord_t ry ) 74 { rx=px; ry=py; } 75 76 void rotCrd90( coord_t px, coord_t py, coord_t sx, coord_t sy, 77 ref coord_t rx, ref coord_t ry ) 78 { rx=sy-1-py; ry=px; } 79 80 void rotCrd180( coord_t px, coord_t py, coord_t sx, coord_t sy, 81 ref coord_t rx, ref coord_t ry ) 82 { rx=sx-1-px; ry=sy-1-py; } 83 84 void rotCrd270( coord_t px, coord_t py, coord_t sx, coord_t sy, 85 ref coord_t rx, ref coord_t ry ) 86 { rx=py; ry=sx-1-px; } 87 88 void mirHorCrd( coord_t px, coord_t py, coord_t sx, coord_t sy, 89 ref coord_t rx, ref coord_t ry ) 90 { rx=sx-1-px; ry=py; } 91 92 void mirVerCrd( coord_t px, coord_t py, coord_t sx, coord_t sy, 93 ref coord_t rx, ref coord_t ry ) 94 { rx=px; ry=sy-1-py; } 95 96 void mTransCrd( coord_t px, coord_t py, coord_t sx, coord_t sy, 97 ref coord_t rx, ref coord_t ry ) 98 { rx=py; ry=px; } 99 100 void sTransCrd( coord_t px, coord_t py, coord_t sx, coord_t sy, 101 ref coord_t rx, ref coord_t ry ) 102 { rx=sy-1-py; ry=sx-1-px; } 103 } 104 105 /// copy `src` image from `copy_reg` to `dst` image in `paste_pos` with repack 106 void imCopy( string file=__FILE__, size_t line=__LINE__, size_t A, 107 size_t B, T, E)( ref Image dst, in Vector!(A,T) paste_pos, 108 in Image src, in Region!(B,E) copy_reg, 109 ImRepack repack=ImRepack.NONE, size_t[2] repack_dim=[0,1] ) 110 if( isIntegral!T && isIntegral!E ) 111 { 112 auto dims = dst.dims; 113 imEnforce!(file,line)( dims > 0, "no dimensions in dst" ); 114 imEnforce!(file,line)( src.dims > 0, "no dimensions in src" ); 115 imEnforce!(file,line)( dims >= src.dims, 116 "too much source dimensions" ); 117 imEnforce!(file,line)( dims == paste_pos.length, 118 "dst dims mismatch with dst_pos dims" ); 119 imEnforce!(file,line)( dims == copy_reg.dims, 120 "dst dims mismatch with src_reg dims" ); 121 imEnforce!(file,line)( repack_dim[0] < dims, 122 "repack_dim[0] not less what dst dims" ); 123 imEnforce!(file,line)( dst.info == src.info, 124 "dst info mismatch with src info" ); 125 126 auto rd0 = repack_dim[0]; 127 auto rd1 = repack_dim[1]; 128 129 if( dims == 1 ) rd1 = rd0; 130 else imEnforce!(file,line)( rd1 < dims, 131 "repack_dim[1] not less what dst dims" ); 132 133 auto src_size = src.robSize(dims); 134 135 imEnforce!(file,line)( isAllCompPositive(copy_reg.pos), 136 "copy region must be in source image" ); 137 imEnforce!(file,line)( isAllCompPositive(src_size-copy_reg.lim), 138 "copy region must be in source image" ); 139 140 auto paste_reg = CrdRegionD( paste_pos, 141 permutateComp( copy_reg.size, repack, repack_dim ) ); 142 143 auto crop = CrdRegionD.fromSize( dst.size ).overlapLocal( paste_reg ); 144 145 auto copy_count = reduce!((s,v)=>s*=v)( crop.size ); 146 147 auto repack_crd_func = getRepackCrdFunc( repack ); 148 149 auto bpe = dst.info.bpe; 150 151 foreach( i; 0 .. copy_count ) 152 { 153 auto local_crop_crd = CrdVectorD( getCoord( crop.size, i ) ); 154 155 auto dst_crd = crop.pos + local_crop_crd; 156 157 auto dst_offset = getIndex( dst.size, dst_crd ); 158 159 auto paste_crd = dst_crd - paste_reg.pos; 160 auto src_crd = CrdVectorD( paste_crd ); 161 162 repack_crd_func( paste_crd[rd0], paste_crd[rd1], 163 paste_reg.size[rd0], paste_reg.size[rd1], 164 src_crd[rd0], src_crd[rd1] ); 165 166 auto src_offset = getIndex( src_size, src_crd + copy_reg.pos ); 167 168 memcpy( dst.data.ptr + dst_offset * bpe, 169 src.data.ptr + src_offset * bpe, bpe ); 170 } 171 } 172 173 /// 174 unittest 175 { 176 auto etype = ElemInfo( 1, DataType.INT ); 177 auto dst = Image( ivec2(3,3), etype ); 178 179 auto src = Image( ivec2(2,2), etype, [ 1,2, 3,4 ]); 180 181 imCopy( dst, ivec2(1,1), src, CrdRegionD(0,0,2,2), ImRepack.ROT90 ); 182 183 assertEq( dst.data, [ 0,0,0, 184 0,2,4, 185 0,1,3 ] ); 186 187 imCopy( dst, ivec2(0,0), src, CrdRegionD(0,0,2,2), ImRepack.ROT270 ); 188 189 assertEq( dst.data, [ 3,1,0, 190 4,2,4, 191 0,1,3 ] ); 192 } 193 194 /// 195 unittest 196 { 197 auto etype = ElemInfo( 1, DataType.INT ); 198 auto dst = Image( ivec3(3,3,3), etype ); 199 auto src = Image( CrdVectorD(3), etype, [1,2,4] ); 200 201 imCopy( dst, ivec3(0,0,0), src, CrdRegionD(0,0,0,3,1,1), ImRepack.ROT270 ); 202 assertEq( dst.mapAs!int, [ 1,0,0, 203 2,0,0, 204 4,0,0, // z=0 205 206 0,0,0, 207 0,0,0, 208 0,0,0, // z=1 209 210 0,0,0, 211 0,0,0, 212 0,0,0, // z=2 213 ] ); 214 215 imCopy( dst, ivec3(1,0,0), src, CrdRegionD(0,0,0,3,1,1), ImRepack.ROT90, [0,2] ); 216 assertEq( dst.mapAs!int, [ 1,4,0, 217 2,0,0, 218 4,0,0, // z=0 219 220 0,2,0, 221 0,0,0, 222 0,0,0, // z=1 223 224 0,1,0, 225 0,0,0, 226 0,0,0, // z=2 227 ] ); 228 } 229 230 /// 231 unittest 232 { 233 auto etype = ElemInfo( 1, DataType.INT ); 234 auto dst = Image( ivec3(3,3,3), etype ); 235 auto src = Image( CrdVectorD(3), etype, [1,2,4] ); 236 237 imCopy( dst, ivec3(1,0,0), src, CrdRegionD(1,0,0,2,1,1), ImRepack.ROT270 ); 238 assertEq( dst.mapAs!int, [ 0,2,0, 239 0,4,0, 240 0,0,0, // z=0 241 242 0,0,0, 243 0,0,0, 244 0,0,0, // z=1 245 246 0,0,0, 247 0,0,0, 248 0,0,0, // z=2 249 ] ); 250 } 251 252 /// 253 void imCopy(string file=__FILE__, size_t line=__LINE__, size_t A,T) 254 ( ref Image dst, in Vector!(A,T) paste_pos, 255 in Image src, ImRepack repack=ImRepack.NONE, 256 size_t[2] repack_dim=[0,1] ) 257 if( isIntegral!T ) 258 { 259 imCopy!(file,line)( dst, paste_pos, src, 260 CrdRegionD.fromSize( src.robSize(dst.dims) ), 261 repack, repack_dim ); 262 } 263 264 /// 265 unittest 266 { 267 auto etype = ElemInfo( 1, DataType.INT ); 268 auto dst = Image( ivec2(4,4), etype ); 269 auto src = Image( ivec2(3,2), etype, [ 1,2,4, 5,6,8 ] ); 270 271 imCopy( dst, ivec2(-1,-1), src, ImRepack.ROT90 ); 272 assertEq( dst.mapAs!int, [ 6,0,0,0, 273 5,0,0,0, 274 0,0,0,0, 275 0,0,0,0 ] ); 276 imCopy( dst, ivec2(2,1), src, ImRepack.ROT180 ); 277 assertEq( dst.mapAs!int, [ 6,0,0,0, 278 5,0,8,6, 279 0,0,4,2, 280 0,0,0,0 ] ); 281 imCopy( dst, ivec2(-1,3), src, ImRepack.MIRVER ); 282 assertEq( dst.mapAs!int, [ 6,0,0,0, 283 5,0,8,6, 284 0,0,4,2, 285 6,8,0,0 ] ); 286 } 287 288 /// 289 unittest 290 { 291 auto etype = ElemInfo( 1, DataType.INT ); 292 auto dst = Image( ivec2(2,2), etype ); 293 auto src = Image( ivec2(3,3), etype, [ 1,2,4, 5,6,8, 9,7,3 ] ); 294 295 imCopy( dst, ivec2(-1,-1), src, CrdRegionD(0,0,3,3) ); 296 assertEq( dst.mapAs!int, [ 6,8, 297 7,3 ] ); 298 299 } 300 301 /// 302 unittest 303 { 304 auto etype = ElemInfo( 1, DataType.INT ); 305 auto dst = Image( ivec3(2,2,2), etype ); 306 auto src = Image( ivec!1(2), etype, [ 1,2 ] ); 307 308 imCopy( dst, ivec3(0,0,0), src, ImRepack.NONE ); 309 assertEq( dst.mapAs!int, [1,2, 0,0, 0,0, 0,0] ); 310 311 imCopy( dst, ivec3(0,0,0), src, ImRepack.ROT270 ); 312 assertEq( dst.mapAs!int, [1,2, 2,0, 0,0, 0,0] ); 313 314 dst.clear(); 315 imCopy( dst, ivec3(0,0,0), src, ImRepack.ROT90, [0,2] ); 316 assertEq( dst.mapAs!int, [2,0, 0,0, 1,0, 0,0] ); 317 } 318 319 /// copy and repack image from region to new image 320 Image imGetCopy(string file=__FILE__,size_t line=__LINE__,size_t B,E)( in Image src, in Region!(B,E) copy_reg, 321 ImRepack repack=ImRepack.NONE, size_t[2] repack_dim=[0,1] ) 322 if( isIntegral!E ) 323 { 324 if( src.dims == 1 ) repack_dim[1] = repack_dim[0]; 325 auto sz = permutateComp( copy_reg.size, repack, repack_dim ); 326 auto ret = Image( sz, src.info ); 327 imCopy!(file,line)( ret, CrdVectorD.fill(src.dims,0), src, copy_reg, repack, repack_dim ); 328 return ret; 329 } 330 331 /// 332 unittest 333 { 334 auto a = Image( ivec!1(5), ElemInfo( 2, DataType.FLOAT ) ); 335 a.pixel!vec2(3) = vec2(1,1); 336 a.pixel!vec2(4) = vec2(2,2); 337 auto b = imGetCopy( a, Region!(1,int)(3,2) ); 338 assert( b.pixel!vec2(0) == a.pixel!vec2(3) ); 339 assert( b.pixel!vec2(1) == a.pixel!vec2(4) ); 340 } 341 342 /// 343 unittest 344 { 345 ubyte[] imgdata = [ 346 1, 2, 3, 4, 347 5, 6, 7, 8, 348 9,10,11,12, 349 13,14,15,16 350 ]; 351 352 auto img = Image( ivec2(4,4), 1, DataType.UBYTE, imgdata ); 353 354 { 355 ubyte[] r = [ 8,12,16, 7,11,15 ]; 356 assertEq( imGetCopy( img, iRegion2(2,1,2,3), ImRepack.ROT90 ).mapAs!ubyte, r ); 357 } 358 359 { 360 ubyte[] r = [ 14,10,6, 15,11,7 ]; 361 assertEq( imGetCopy( img, iRegion2(1,1,2,3), ImRepack.ROT270 ).mapAs!ubyte, r ); 362 } 363 364 { 365 ubyte[] r= [ 3,2,1, 7,6,5 ]; 366 assertEq( imGetCopy( img, iRegion2(0,0,3,2), ImRepack.MIRHOR ).mapAs!ubyte, r ); 367 } 368 369 { 370 ubyte[] r = [ 5,6,7, 1,2,3 ]; 371 assert( imGetCopy( img, iRegion2(0,0,3,2), ImRepack.MIRVER ).mapAs!ubyte == r ); 372 } 373 } 374 375 /// 376 unittest 377 { 378 ubyte[] img_data = 379 [ 380 1,2,3, 381 4,5,6, 382 383 7,8,9, 384 10,11,12, 385 ]; 386 387 ubyte[] d2l0 = [ 1,2,3,4,5,6 ]; 388 ubyte[] d2l1 = [ 7,8,9,10,11,12 ]; 389 390 ubyte[] d1l0 = [ 1,2,3,7,8,9 ]; 391 ubyte[] d1l1 = [ 4,5,6,10,11,12 ]; 392 393 ubyte[] d0l0 = [ 1, 4, 7, 10 ]; 394 ubyte[] d0l1 = [ 2, 5, 8, 11 ]; 395 396 auto img = Image( ivec3(3,2,2), 1, DataType.UBYTE, img_data ); 397 398 assertEq( imGetCopy( img, CrdRegionD(0,0,0,3,2,1) ).mapAs!ubyte, d2l0 ); 399 assertEq( imGetCopy( img, CrdRegionD(0,0,1,3,2,1) ).mapAs!ubyte, d2l1 ); 400 401 assertEq( imGetCopy( img, CrdRegionD(0,0,0,3,1,2) ).mapAs!ubyte, d1l0 ); 402 assertEq( imGetCopy( img, CrdRegionD(0,1,0,3,1,2) ).mapAs!ubyte, d1l1 ); 403 404 assertEq( imGetCopy( img, CrdRegionD(0,0,0,1,2,2) ).mapAs!ubyte, d0l0 ); 405 assertEq( imGetCopy( img, CrdRegionD(1,0,0,1,2,2) ).mapAs!ubyte, d0l1 ); 406 } 407 408 /// 409 unittest 410 { 411 ubyte[] data = 412 [ 413 2, 1, 3, 5, 2, 414 9, 1, 2, 6, 3, 415 2, 5, 2, 9, 1, 416 8, 3, 6, 3, 0, 417 6, 2, 8, 1, 5 418 ]; 419 420 ubyte[] datav1 = 421 [ 422 1, 2, 6, 3, 0, 0, 0, 423 5, 2, 9, 1, 0, 0, 0, 424 3, 6, 3, 0, 0, 0, 0, 425 2, 8, 1, 5, 0, 0, 0, 426 0, 0, 0, 0, 0, 0, 0, 427 0, 0, 0, 0, 0, 0, 0, 428 0, 0, 0, 0, 0, 0, 0 429 ]; 430 431 ubyte[] datav2 = 432 [ 433 0, 0, 0, 0, 0, 0, 0, 434 0, 2, 1, 3, 5, 2, 0, 435 0, 9, 1, 2, 6, 3, 0, 436 0, 2, 5, 2, 9, 1, 0, 437 0, 8, 3, 6, 3, 0, 0, 438 0, 6, 2, 8, 1, 5, 0, 439 0, 0, 0, 0, 0, 0, 0 440 ]; 441 442 443 auto orig = Image( ivec2( 7, 7 ), ElemInfo( 1, DataType.UBYTE ) ); 444 auto im = Image( ivec2( 5, 5 ), 1, DataType.UBYTE, data ); 445 446 auto res = Image(orig); 447 imCopy( res, ivec2(-1,-1), im ); 448 assert( res.data == datav1 ); 449 450 res = Image(orig); 451 imCopy( res, ivec2(1,1), im ); 452 assert( res.data == datav2 ); 453 } 454 455 unittest 456 { 457 ubyte[] src_data = [ 1,2,3, 4,5,6, 7,8,9 ]; 458 459 ubyte[] dst1_data = 460 [ 461 0,0,0, 0,0,0, 0,0,0, 462 463 1,2,3, 4,5,6, 7,8,9, 464 465 0,0,0, 0,0,0, 0,0,0 466 ]; 467 468 ubyte[] dst2_data = 469 [ 470 0,1,0, 0,2,0, 0,3,0, 471 472 0,4,0, 0,5,0, 0,6,0, 473 474 0,7,0, 0,8,0, 0,9,0 475 ]; 476 477 auto src = Image( ivec2(3,3), ElemInfo( 1, DataType.UBYTE ), src_data ); 478 auto dst = Image( ivec3(3,3,3), ElemInfo( 1, DataType.UBYTE ) ); 479 imCopy( dst, ivec3(0,0,1), Image( ivec3(3,3,1), src.info, src.data ) ); 480 assert( dst.data == dst1_data ); 481 dst.clear(); 482 imCopy( dst, ivec3(1,0,0), Image.external( ivec3(1,3,3), src.info, src.data ) ); 483 assertEq( dst.data, dst2_data ); 484 } 485 486 unittest 487 { 488 ubyte[] dt = 489 [ 490 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 491 492 0,0,0,0, 0,1,2,0, 0,3,4,0, 0,0,0,0, 493 494 0,0,0,0, 0,5,6,0, 0,7,8,0, 0,0,0,0, 495 496 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 497 ]; 498 499 ubyte[] cp = 500 [ 501 1,2,1,2, 3,4,3,4, 1,2,1,2, 3,4,3,4, 502 503 5,6,5,6, 7,8,7,8, 5,6,5,6, 7,8,7,8, 504 505 1,2,1,2, 3,4,3,4, 1,2,1,2, 3,4,3,4, 506 507 5,6,5,6, 7,8,7,8, 5,6,5,6, 7,8,7,8, 508 ]; 509 510 ubyte[] rs = [ 8,7, 6,5, 4,3, 2,1 ]; 511 512 auto EType = ElemInfo( 1, DataType.UBYTE ); 513 514 auto a = Image( ivec3(4,4,4), EType, dt ); 515 auto b = Image( ivec3(4,4,4), EType, cp ); 516 auto c = Image( ivec3(4,4,4), EType ); 517 518 auto part = imGetCopy( a, iRegion3( ivec3(1,1,1), ivec3(2,2,2) ) ); 519 520 imCopy( c, ivec3(0,0,0), part ); 521 imCopy( c, ivec3(0,2,0), part ); 522 imCopy( c, ivec3(2,0,0), part ); 523 imCopy( c, ivec3(2,2,0), part ); 524 525 imCopy( c, ivec3(0,0,2), part ); 526 imCopy( c, ivec3(0,2,2), part ); 527 imCopy( c, ivec3(2,0,2), part ); 528 imCopy( c, ivec3(2,2,2), part ); 529 530 assert( b == c ); 531 532 auto part2 = imGetCopy( b, iRegion3(ivec3(1,1,1), ivec3(2,2,2)) ); 533 auto rr = Image( ivec3(2,2,2), EType, rs ); 534 assert( rr == part2 ); 535 } 536 537 unittest 538 { 539 auto type = ElemInfo(1,DataType.UBYTE); 540 541 ubyte[] srcData = 542 [ 543 1,2,3, 544 4,5,6, 545 ]; 546 547 auto src = Image( ivec2(3,2), type, srcData ); 548 auto dst = Image( ivec3(3,3,3), type ); 549 imCopy( dst, ivec3(1,0,0), src, ImRepack.ROT180 ); 550 imCopy( dst, ivec3(-1,-1,1), src, ImRepack.ROT90 ); 551 imCopy( dst, ivec3(0,0,2), src, ImRepack.NONE ); 552 553 auto expectedDstData = 554 [ 555 0,6,5, 0,3,2, 0,0,0, 556 557 5,0,0, 4,0,0, 0,0,0, 558 559 1,2,3, 4,5,6, 0,0,0, 560 ]; 561 562 assertEq( expectedDstData, dst.mapAs!ubyte ); 563 } 564 565 // TODO: utDataAssign utDataOp 566 ///++ get histogram convolution 567 // +/ 568 //Image imHistoConv( in Image img, size_t dim ) pure 569 //in { assert( dim < img.dims ); } body 570 //{ 571 // auto ret = Image( ivecD( cut( img.size, dim ) ), img.info ); 572 // 573 // auto bpe = img.info.bpe; 574 // 575 // foreach( i; 0 .. ret.pixelCount ) 576 // { 577 // auto buf = ret.data.ptr + i * bpe; 578 // utDataAssign( img.info, buf, 0 ); 579 // foreach( j; 0 .. img.size[dim] ) 580 // utDataOp!"+"( img.info, buf, 581 // cast(void*)( img.data.ptr + getOrigIndexByLayerCoord( img.size, dim, i, j ) * bpe ) ); 582 // } 583 // 584 // return ret; 585 //} 586 // 587 ///// 588 //unittest 589 //{ 590 // ubyte[] img_data = 591 // [ 592 // 1,2,5,8, 593 // 4,3,1,1 594 // ]; 595 // 596 // ubyte[] hi_x_data = [ 16, 9 ]; 597 // ubyte[] hi_y_data = [ 5, 5, 6, 9 ]; 598 // 599 // auto img = Image( ivec2(4,2), ElemInfo( 1, DataType.UBYTE ), img_data ); 600 // auto hi_x = Image( ivec!1(2), ElemInfo( 1, DataType.UBYTE ), hi_x_data ); 601 // auto hi_y = Image( ivec!1(4), ElemInfo( 1, DataType.UBYTE ), hi_y_data ); 602 // 603 // assert( imHistoConv(img,0) == hi_x ); 604 // assert( imHistoConv(img,1) == hi_y ); 605 //}