23 #include <Base/Common/W32Compat.hh>
24 #include "ImageDraw.hh"
26 #include <Base/ImageUtils/Bresenham.hh>
27 #include <Base/ImageUtils/BresenhamCircle.hh>
28 #include <Base/ImageUtils/BresenhamCircleEighth.hh>
29 #include <Base/Image/ColourRGB.hh>
30 #include <Base/Image/ImageConvert.hh>
32 #ifdef BIAS_HAVE_OPENCV
33 # include <Base/Image/WrapBias2Ipl.hh>
37 #ifdef BIAS_HAVE_IMAGEMAGICKLIB
38 # include <Base/Common/BIASpragmaStart.hh>
39 # include <Magick++.h>
40 # include <Base/Common/BIASpragmaEnd.hh>
41 # if (MagickLibVersion >= 0x650)
42 # define MagickLib MagickCore
47 #ifdef BIAS_IMAGEMAGICKLIB_V2
48 # define MagickLib MagickCore
49 #endif //BIAS_IMAGEMAGICKLIB_V2
57 template <
class StorageType>
61 BIASERR(
"Don't know what would be a good contrast value for "
62 <<(
double)t<<
" for StorageType "<<PRINTTYPE(StorageType));
64 if (numeric_limits<StorageType>::is_signed){
65 thresh = numeric_limits<StorageType>::min();
67 thresh = (StorageType)(( numeric_limits<StorageType>::max()-
68 numeric_limits<StorageType>::min() )/(StorageType)2.0);
70 return (t>thresh)?(numeric_limits<StorageType>::min()):
71 (numeric_limits<StorageType>::max());
78 return float((t>0.0)?-1.0:1.0);
85 return (
unsigned char)((t > 127) ? 0 : 255);
92 template <
class StorageType>
95 const int amaxx,
const int amaxy,
96 const StorageType Value[])
98 const int minx = (aminx<amaxx)?(aminx):(amaxx);
99 const int maxx = (amaxx>aminx)?(amaxx):(aminx);
100 const int miny = (aminy<amaxy)?(aminy):(amaxy);
101 const int maxy = (amaxy>aminy)?(amaxy):(aminy);
105 register int x, y, c, xp1, xp2;
108 for (x = minx; x <= maxx; x++){
111 for (c=0; c<cc; c++){
112 if (miny>=0 && miny<h) { ida[miny][xp1+c]=Value[c]; }
113 if (maxy>=0 && maxy<h) { ida[maxy][xp1+c]=Value[c]; }
120 for (y = miny; y <= maxy; y++){
122 for (c=0; c<cc; c++){
123 if (minx>=0 && minx<w) { ida[y][xp1+c]=Value[c]; }
124 if (maxx>=0 && maxx<w) { ida[y][xp2+c]=Value[c]; }
128 return (minx>=0 && miny>=0 && maxx<w && maxy<h)?(0):(-1);
132 template <
class StorageType>
135 const int maxx,
const int maxy,
const StorageType value)
140 int res = RectangleCorners(im, minx, miny, maxx, maxy, val);
146 template <
class StorageType>
149 const int aminy,
const int amaxx,
const int amaxy)
151 const int minx = (aminx<amaxx)?(aminx):(amaxx);
152 const int maxx = (amaxx>aminx)?(amaxx):(aminx);
153 const int miny = (aminy<amaxy)?(aminy):(amaxy);
154 const int maxy = (amaxy>aminy)?(amaxy):(aminy);
158 register int x, y, c, xp1, xp2;
161 for (x = minx; x <= maxx; x++){
164 for (c=0; c< cc; c++){
165 if (miny>=0 && miny<h) {
166 ida[miny][xp1+c]=GetContrastValue(ida[miny][xp1+c]);
168 if (maxy>=0 && maxy<h) {
169 ida[maxy][xp1+c]=GetContrastValue(ida[maxy][xp1+c]);
177 for (y = miny; y <= maxy; y++){
179 for (c=0; c< cc; c++){
180 if (minx>=0 && minx<w) {
181 ida[y][xp1+c]=GetContrastValue(ida[y][xp1+c]);
183 if (maxx>=0 && maxx<w) {
184 ida[y][xp2+c]=GetContrastValue(ida[y][xp2+c]);
189 return (minx>=0 && miny>=0 && maxx<w && maxy<h)?(0):(-1);
192 template <
class StorageType>
195 const int amaxx,
const int amaxy,
196 const StorageType Value[])
199 const int minx = (aminx<amaxx)?(aminx):(amaxx);
200 const int maxx = ((amaxx>aminx)?(amaxx):(aminx)) * cc;
201 const int miny = (aminy<amaxy)?(aminy):(amaxy);
202 const int maxy = (amaxy>aminy)?(amaxy):(aminy);
206 register int x, y, c;
210 for (x = minx*cc; x <= maxx; x+=cc)
211 for (y = miny; y <= maxy; y++)
212 for (c = 0; c < cc; c++)
213 ida[y][x+c] = Value[c];
215 return (minx>=0 && miny>=0 && maxx<w && maxy<h)?(0):(-1);
219 template <
class StorageType>
222 const int aminy,
const int amaxx,
223 const int amaxy,
const StorageType GreyValue)
226 BEXCEPTION(
"ImageDraw::RectangleCornersGrey() is only for single "
229 const int minx = (aminx<amaxx)?(aminx):(amaxx);
230 const int maxx = (amaxx>aminx)?(amaxx):(aminx);
231 const int miny = (aminy<amaxy)?(aminy):(amaxy);
232 const int maxy = (amaxy>aminy)?(amaxy):(aminy);
238 for (x = minx; x <= maxx; x++){
240 if (miny>=0 && miny<h) { ida[miny][x]=GreyValue; }
241 if (maxy>=0 && maxy<h) { ida[maxy][x]=GreyValue; }
245 for (y = miny; y <= maxy; y++){
247 if (minx>=0 && minx<w) { ida[y][x]=GreyValue; }
248 if (maxx>=0 && maxx<w) { ida[y][x]=GreyValue; }
251 return (minx>=0 && miny>=0 && maxx<w && maxy<h)?(0):(-1);
255 template <
class StorageType>
258 const int aminy,
const int amaxx,
259 const int amaxy,
const StorageType GreyValue)
261 const int minx = (aminx<amaxx)?(aminx):(amaxx);
262 const int maxx = (amaxx>aminx)?(amaxx):(aminx);
263 const int miny = (aminy<amaxy)?(aminy):(amaxy);
264 const int maxy = (amaxy>aminy)?(amaxy):(aminy);
266 const int mmaxx = (maxx>w)?(w):(maxx);
267 const int mmaxy = (maxy>h)?(h):(maxy);
272 for (y=miny; y<mmaxy; y++){
273 for (x=minx; x<mmaxx; x++){
274 ida[y][x] = GreyValue;
278 return (minx>=0 && miny>=0 && maxx<w && maxy<h)?(0):(-1);
282 template <
class StorageType>
285 const int Y,
const int Size,
286 const StorageType Value[])
288 const int Halfsize = Size >> 1;
290 return RectangleCornersGrey(im, (X>Halfsize)?X-Halfsize:0,
291 (Y>Halfsize)?Y-Halfsize:0,
293 (X+Halfsize):((int)im.
GetWidth()-1),
298 return RectangleCorners(im, (X>Halfsize)?X-Halfsize:0,
299 (Y>Halfsize)?Y-Halfsize:0,
301 (X+Halfsize):((int)im.
GetWidth()-1),
309 template <
class StorageType>
312 const int Y,
const int Size,
313 const StorageType Value)
315 const int Halfsize = Size >> 1;
316 return RectangleCornersGrey(im, (X>Halfsize)?X-Halfsize:0,
317 (Y>Halfsize)?Y-Halfsize:0,
319 (X+Halfsize):((int)im.
GetWidth()-1),
326 template <
class StorageType>
329 const int Y,
const int Size,
330 const StorageType Value)
332 const int Halfsize = Size >> 1;
333 return RectangleCornersGreyFill(im, (X>Halfsize)?X-Halfsize:0,
334 (Y>Halfsize)?Y-Halfsize:0,
336 (X+Halfsize):((int)im.
GetWidth()-1),
343 template <
class StorageType>
346 const int y,
const int size)
348 const int Halfsize = size >> 1;
349 return RectangleCorners(im, (x>Halfsize)?x-Halfsize:0,
350 (y>Halfsize)?y-Halfsize:0,
352 (x+Halfsize):((int)im.
GetWidth()-1),
358 template <
class StorageType>
362 {
return RectangleCenter(im, coo[0], coo[1], size); }
370 template <
class StorageType>
373 const int end[2],
const StorageType value[])
385 if (next[0]<0 || next[0]>=w || next[1]<0 || next[1]>=h){
391 ida[next[1]][xcc+c] = value[c];
395 BIASWARN(
"Line is (partially) outside of image: (" << start[0] <<
", "
396 << start[1] <<
") - (" << end[0] <<
", " << end[1] <<
")!");
402 template <
class StorageType>
405 const unsigned int end[2],
const StorageType value[])
409 if (start[0]>=(
unsigned)numeric_limits<int>::max() ||
410 start[1]>=(
unsigned)numeric_limits<int>::max() ||
411 end[0]>=(
unsigned)numeric_limits<int>::max() ||
412 end[1]>=(
unsigned)numeric_limits<int>::max() ) {
413 BIASWARN(
"Conversion from int to unsigned int failed!");
417 int start0 = start[0], start1 = start[1];
418 int istart[] = { start0, start1 };
419 int end0 = end[0], end1 = end[1];
420 int iend[] = { end0, end1 };
421 return Line(im, istart, iend, value);
425 template <
class StorageType>
429 const StorageType value[],
433 float m = fabs(static_cast<float>(end[1]-start[1]))/fabs(static_cast<float>(end[0]-start[0]));
434 int offset[2] = {0,0};
445 for(
int i=-width; i<=width; i++) {
447 startUsed[0] = start[0]+ i*offset[0];
448 startUsed[1] = start[1]+ i*offset[1];
449 endUsed[0] = end[0]+ i*offset[0];
450 endUsed[1] = end[1]+ i*offset[1];
455 next[0]=startUsed[0];
456 next[1]=startUsed[1];
460 if (!(next[0]<0 || next[0]>=
int(im.
GetWidth()) ||
461 next[1]<0 || next[1]>=
int(im.
GetHeight()))) {
470 template <
class StorageType>
472 const unsigned int start[2],
473 const unsigned int end[2], StorageType value)
476 if (start[0]<0 || start[0]>=im.
GetWidth() ||
477 start[1]<0 || start[1]>=im.
GetHeight() ||
478 end[0]<0 || end[0]>=im.
GetWidth() ||
480 BIASWARN(
"Line is (partially) outside of image: (" << start[0] <<
", "
481 << start[1] <<
") - (" << end[0] <<
", " << end[1] <<
")!");
485 unsigned int next[2];
499 template <
class StorageType>
501 const unsigned int start[2],
502 const unsigned int end[2],
506 if (start[0]<0 || start[0]>=im.
GetWidth() ||
507 start[1]<0 || start[1]>=im.
GetHeight() ||
508 end[0]<0 || end[0]>=im.
GetWidth() ||
510 BIASWARN(
"Line is (partially) outside of image: (" << start[0] <<
", "
511 << start[1] <<
") - (" << end[0] <<
", " << end[1] <<
")!");
515 BIASWARN(
"Only implemented for one channel images!");
519 unsigned int next[2];
527 ida[next[1]][next[0]]=value;
533 template <
class StorageType>
535 const unsigned int start[2],
536 const unsigned int end[2])
539 if (start[0]<0 || start[0]>=im.
GetWidth() ||
540 start[1]<0 || start[1]>=im.
GetHeight() ||
541 end[0]<0 || end[0]>=im.
GetWidth() ||
543 BIASWARN(
"Line is (partially) outside of image: (" << start[0] <<
", "
544 << start[1] <<
") - (" << end[0] <<
", " << end[1] <<
")!");
548 unsigned int next[2];
564 template <
class StorageType>
566 const unsigned int start[2],
567 const unsigned int end[2])
570 if (start[0]<0 || start[0]>=im.
GetWidth() ||
571 start[1]<0 || start[1]>=im.
GetHeight() ||
572 end[0]<0 || end[0]>=im.
GetWidth() ||
574 BIASWARN(
"Line is (partially) outside of image: (" << start[0] <<
", "
575 << start[1] <<
") - (" << end[0] <<
", " << end[1] <<
")!");
579 BIASWARN(
"Only implemented for one channel images!");
583 unsigned int next[2];
591 ida[next[1]][next[0]]=GetContrastValue(ida[next[1]][next[0]]);
598 template <
class StorageType>
600 const unsigned int StartX,
601 const unsigned int StartY,
602 const unsigned int EndX,
603 const unsigned int EndY,
604 const StorageType Value[])
606 unsigned int start[]={StartX, StartY}, end[]={EndX, EndY};
607 return Line(im, start, end, Value);
611 template <
class StorageType>
613 const unsigned int StartX,
614 const unsigned int StartY,
615 const unsigned int EndX,
616 const unsigned int EndY,
617 const StorageType Value)
619 unsigned int start[]={StartX, StartY}, end[]={EndX, EndY};
620 return Line(im, start, end, Value);
623 template <
class StorageType>
625 const unsigned int StartX,
626 const unsigned int StartY,
627 const unsigned int EndX,
628 const unsigned int EndY)
630 unsigned int start[]={StartX, StartY}, end[]={EndX, EndY};
631 return Line(im, start, end);
636 template <
class StorageType>
638 const unsigned int StartX,
639 const unsigned int StartY,
640 const unsigned int EndX,
641 const unsigned int EndY,
642 const StorageType Value)
644 unsigned int start[]={StartX, StartY}, end[]={EndX, EndY};
645 return LineGrey(im, start, end, Value);
649 #define BIAS_DRAW_CROSS_PRODUCT(a, b, res) \
650 res[0] = a[1] * b[2] - a[2] * b[1]; \
651 res[1] = a[2] * b[0] - a[0] * b[2]; \
652 res[2] = a[0] * b[1] - a[1] * b[0];
654 #define BIAS_DRAW_PRECISION 1e-8
656 template <
class StorageType>
660 const StorageType value[])
664 double wm=(double)(w-1);
665 double hm=(double)(h-1);
666 unsigned uistart[2], uiend[2];
667 double s[]={start[0], start[1], 1.0}, e[]={end[0], end[1], 1.0};
672 BIAS_DRAW_CROSS_PRODUCT(s, e, line);
676 double top[]={0, -1.0, 0.0}, bottom[]={0.0, -1.0, hm};
677 double left[]={-1.0, 0.0, 0.0}, right[]={-1.0, 0.0, wm};
678 double intersections[4][3];
679 BIAS_DRAW_CROSS_PRODUCT(line, left, intersections[0]);
680 BIAS_DRAW_CROSS_PRODUCT(line, right, intersections[1]);
681 BIAS_DRAW_CROSS_PRODUCT(line, top, intersections[2]);
682 BIAS_DRAW_CROSS_PRODUCT(line, bottom, intersections[3]);
684 unsigned coo[4]={0,0,0,0};
686 int intersectioncount=0;
688 for (
unsigned int i=0; i<4; i++){
689 if (fabs(intersections[i][0]) < BIAS_DRAW_PRECISION)
690 intersections[i][0] = 0.0;
691 if (fabs(intersections[i][1]) < BIAS_DRAW_PRECISION)
692 intersections[i][1] = 0.0;
693 if (fabs(intersections[i][0]-wm) < BIAS_DRAW_PRECISION)
694 intersections[i][0] = wm;
695 if (fabs(intersections[i][1]-hm) < BIAS_DRAW_PRECISION)
696 intersections[i][1] = hm;
697 if (fabs(intersections[i][2]) < BIAS_DRAW_PRECISION){
698 intersections[i][2] = 0.0;
701 intersections[i][0]/=intersections[i][2];
702 intersections[i][1]/=intersections[i][2];
709 if (intersect[0] && intersections[0][1]>=0 && intersections[0][1]<=hm){
712 coo[1] = (
unsigned int)rint(intersections[0][1]);
715 if (intersect[1] && intersections[1][1]>=0 && intersections[1][1]<=hm){
716 if (intersectioncount==0){
718 coo[1] = (
unsigned int)rint(intersections[1][1]);
721 coo[3] = (
unsigned int)rint(intersections[1][1]);
726 if (intersect[2] && intersections[2][0]>=0 && intersections[2][0]<=wm){
727 switch (intersectioncount){
729 coo[0] = (
unsigned int)rint(intersections[2][0]);
733 coo[2] = (
unsigned int)rint(intersections[2][0]);
745 if (intersect[3] && intersections[3][0]>=0 && intersections[3][0]<=wm){
746 switch (intersectioncount){
748 coo[0] = (
unsigned int)rint(intersections[3][0]);
752 coo[2] = (
unsigned int)rint(intersections[3][0]);
760 coo[0] = (
unsigned int)rint(intersections[3][0]);
771 if (intersectioncount>1){
774 if (start[0]>=0.0 && start[0]<=wm && start[1]>=0.0 && start[1]<=hm){
776 uistart[0]=(unsigned)rint(start[0]);
777 uistart[1]=(unsigned)rint(start[1]);
782 double dex = end[0]-coo[0], dey = end[1]-coo[1];
783 double dx = end[0]-start[0], dy = end[1]-start[1];
784 if (dx*dex+dy*dey>0.0){
793 if (start[0]>=0.0 && start[0]<=wm && start[1]>=0.0 && start[1]<=hm){
795 uiend[0]=(unsigned)rint(end[0]);
796 uiend[1]=(unsigned)rint(end[1]);
801 double dex = start[0]-coo[0], dey = start[1]-coo[1];
802 double dx = start[0]-end[0], dy = start[1]-end[1];
803 if (dx*dex+dy*dey>0.0){
811 return Line(im, uistart, uiend, value);
818 #undef BIAS_DRAW_CROSS_PRODUCT
819 #undef BIAS_DRAW_PRECISION
825 template <
class StorageType>
831 const StorageType Value[],
832 const float Thickness,
835 return InterpolatedLine(im,
HomgPoint2D((
float)StartX,(
float)StartY,1.0),
841 template <
class StorageType>
845 const StorageType Value[],
846 const float Thickness,
853 float opac = min(fabs(Opacity),1.0f);
857 float LeftX, RightX, LeftY,RightY;
859 if (Start[0] < End[0]){
860 LeftX = (float)Start[0]; LeftY = (float)Start[1];
861 RightX = (float)End[0]; RightY = (float)End[1];
863 LeftX = (float)End[0]; LeftY = (float)End[1];
864 RightX = (float)Start[0]; RightY = (float)Start[1];
868 float MinY = (float)min(Start[1],End[1]) - Thickness;
869 float MaxY = (float)max(Start[1],End[1]) + Thickness;
872 int ClipLeft = max((
int)floor(LeftX-Thickness),0);
873 int ClipRight = min((
int)ceil(RightX+Thickness),(
int)im.
GetWidth()-1);
877 slope = (float)(RightY-LeftY) / (float)(RightX - LeftX);
881 float length = sqrt(((
float)End[0]-(
float)Start[0])*((
float)End[0]-(
float)Start[0])
882 +((
float)End[1]-(
float)Start[1])*((
float)End[1]-(
float)Start[1]));
885 float angle = atan2(RightY - LeftY,RightX-LeftX);
886 float sinAngle = sin(angle);
887 float cosAngle = cos(angle);
889 for (
int xDrawPos = ClipLeft ; xDrawPos <= ClipRight ; xDrawPos++ ){
892 ((float)xDrawPos-LeftX-Thickness)*slope;
894 ((float)xDrawPos-LeftX+Thickness)*slope;
895 float LowerY, UpperY;
897 LowerY = Y1 -Thickness;
898 UpperY = Y2 + Thickness;
900 LowerY = Y2 -Thickness;
901 UpperY = Y1 + Thickness;
905 LowerY = max(ceil(LowerY),ceil(MinY));
906 UpperY = min(floor(UpperY),floor(MaxY));
909 int ClipUp = max((
int)floor(LowerY-1),0);
910 int ClipLow = min((
int)ceil(UpperY)+1,(
int)im.
GetHeight()-1);
913 for (
int yDrawPos = ClipUp; yDrawPos <= ClipLow; yDrawPos++){
915 float xRotated = sinAngle*((float)yDrawPos-LeftY) + cosAngle*((float)xDrawPos-LeftX);
916 float yRotated = -sinAngle*((float)xDrawPos-LeftX) + cosAngle*((float)yDrawPos-LeftY);
917 float dist = fabs(yRotated);
920 dist = sqrt(yRotated*yRotated + xRotated*xRotated);
922 if (fabs(xRotated)>=length)
923 dist = sqrt(yRotated*yRotated + (fabs(xRotated)-length)*(fabs(xRotated)-length));
925 if (dist < Thickness){
926 dist = max(dist - Thickness + 1.0f,0.0f);
927 float ratio = (1.0f - dist) * opac;
928 for (
unsigned int c = 0; c < cc; c++)
929 ida[yDrawPos][xDrawPos*cc+c] = (StorageType)((1.0 - ratio)*(
double)ida[yDrawPos][xDrawPos*cc+c] +
930 ratio * (double)Value[c]);
938 template <
class StorageType>
942 const StorageType GreyValue,
943 const float Thickness ,
944 const float Opacity )
947 StorageType* color =
new StorageType[channels];
948 for (
int c = 0; c < channels; c++)
949 color[c] = GreyValue;
950 int returnValue = InterpolatedLine(im, Start,End,color,Thickness,Opacity);
955 template <
class StorageType>
961 const StorageType GreyValue,
962 const float Thickness,
965 return InterpolatedLineGrey(im,
HomgPoint2D((
float)StartX,(
float)StartY,1.0),
967 GreyValue,Thickness,Opacity);
976 template <
class StorageType>
978 unsigned int CenterX,
979 unsigned int CenterY,
981 const StorageType Value[])
985 int center[2], next[]={0,0}, radius=(int)Radius;
989 const int width = (int)im.
GetWidth();
991 register unsigned int c;
993 center[0]=(int)CenterX;
994 center[1]=(int)CenterY;
996 bc.
Init(center, radius);
1001 if (next[1]>=0 && next[1]<height &&
1002 next[0]>=0 && next[0]<width) {
1003 for (c=0; c<cc; c++) {
1004 ida[next[1]][next[0]*cc+c]=
1005 GetContrastValue(ida[next[1]][next[0]*cc+c]);
1011 if (next[1]>=0 && next[1]<height &&
1012 next[0]>=0 && next[0]<width) {
1013 for (c=0; c<cc; c++) {
1014 ida[next[1]][next[0]*cc+c]=Value[c];
1022 template <
class StorageType>
1024 unsigned int CenterX,
1025 unsigned int CenterY,
1026 unsigned int Radius,
1027 const StorageType Value[])
1031 int zerocenter[]={0,0};
1032 int center[2], next[2], radius=(int)Radius;
1033 unsigned int start[2], end[2];
1034 const int width = (int)im.
GetWidth();
1036 center[0]=(int)CenterX;
1037 center[1]=(int)CenterY;
1039 if (center[0]<=radius || center[1]<=radius ||
1040 center[0]+radius+1>=width || center[1]+radius+1>=height){
1044 bc.
Init(zerocenter, radius);
1047 start[0]=center[0]+next[0];
1048 start[1]=center[1]+next[1];
1049 end[0]=center[0]-next[0];
1050 end[1]=center[1]+next[1];
1051 Line(im, start, end, Value);
1052 start[0]=center[0]+next[1];
1053 start[1]=center[1]+next[0];
1054 end[0]=center[0]-next[1];
1055 end[1]=center[1]+next[0];
1056 Line(im, start, end, Value);
1057 start[0]=center[0]+next[0];
1058 start[1]=center[1]-next[1];
1059 end[0]=center[0]-next[0];
1060 end[1]=center[1]-next[1];
1061 Line(im, start, end, Value);
1062 start[0]=center[0]+next[1];
1063 start[1]=center[1]-next[0];
1064 end[0]=center[0]-next[1];
1065 end[1]=center[1]-next[0];
1066 Line(im, start, end, Value);
1073 template <
class StorageType>
1077 const StorageType Value[],
1078 const float Thickness ,
1079 const float Opacity )
1084 float opac = min(fabs(Opacity),1.0f);
1085 int leftBorder = (int)floor(Center[0] - Radius - Thickness);
1086 int rightBorder = (int)ceil(Center[0] + Radius+Thickness);
1087 int upperBorder = (int)floor(Center[1] - Radius - Thickness);
1088 int lowerBorder = (int)ceil(Center[1] + Radius + Thickness);
1091 leftBorder = max(0,leftBorder);
1092 rightBorder = min((
int)im.
GetWidth()-1,rightBorder);
1093 upperBorder = max(0,upperBorder);
1094 lowerBorder = min((
int)im.
GetHeight()-1,lowerBorder);
1096 for (
int x = leftBorder; x <= rightBorder; x++)
1097 for (
int y = upperBorder; y <= lowerBorder; y++){
1098 float dist = sqrt(((
float)x-(
float)Center[0])*((
float)x-(
float)Center[0])
1099 +((
float)y-(
float)Center[1])*((
float)y-(
float)Center[1]));
1100 if (fabs(dist-Radius) < Thickness){
1101 dist = max(fabs(dist - Radius)- Thickness + 1.0f,0.0f);
1102 float ratio = (1.0f - dist) * opac;
1103 for (
unsigned int c = 0; c < cc; c++)
1104 ida[y][x*cc+c] = (StorageType)((1.0 - ratio)*(
double)ida[y][x*cc+c] +
1105 ratio * (double)Value[c]);
1113 template <
class StorageType>
1115 unsigned int CenterX,
1116 unsigned int CenterY,
1117 unsigned int Radius,
1118 const StorageType Value[],
1119 const float Thickness,
1120 const float Opacity)
1122 return InterpolatedCircleCenter(im,
HomgPoint2D(CenterX,CenterY,1.0),(
float)Radius,Value,Thickness,Opacity);
1126 template <
class StorageType>
1128 const unsigned start[2],
1129 const unsigned mend[2],
1130 const unsigned length,
1131 const unsigned width,
1132 const StorageType value[])
1134 int dx=(int)mend[0]-(
int)start[0], dy=(int)mend[1]-(
int)start[1];
1135 unsigned end[]={mend[0], mend[1]};
1136 double l = sqrt((
double)dx*(
double)dx+(
double)dy*(
double)dy);
1137 if (l<(
double)length){
1138 unsigned num = (unsigned)ceil( (
double)length / l );
1147 if (Line(im, start[0], start[1], end[0], end[1], value, thick)!=0){
1150 if (dx==0 && dy==0){
1158 for (
unsigned i=0; i<length; i++)
1161 int left[]={0,0}, right[]={0,0};
1162 int lend[2], rend[2];
1163 rend[0]=(int)next[0]-dy;
1164 rend[1]=(int)next[1]+dx;
1165 lend[0]=(int)next[0]+dy;
1166 lend[1]=(int)next[1]-dx;
1169 bres.Init(next, rend);
1170 bres2.
Init(next, lend);
1171 for (
unsigned i=0; i<width; i++){
1172 bres.GetNext(right);
1177 if (right[0]>=0 && right[1]<(
int)im.
GetWidth()){
1179 if (Line(im, end[0], end[1], (
unsigned)(right[0]), (
unsigned)(right[1]),
1184 }
else { res = -1; }
1186 if (left[0]>=0 && left[1]<(
int)im.
GetWidth()){
1188 if (Line(im, end[0], end[1], (
unsigned)(left[0]), (
unsigned)(left[1]),
1193 }
else { res = -1; }
1197 template <
class StorageType>
1199 const unsigned int StartX,
1200 const unsigned int StartY,
1201 const unsigned int EndX,
1202 const unsigned int EndY,
1203 const StorageType color[],
1204 const float thickness )
1206 #ifdef BIAS_HAVE_OPENCV
1207 int i_thickness=int(thickness);
1215 BIASWARNONCE(
"Compile BIAS with OpenCV to draw thick lines! Using slow workaround.");
1221 dir[0] = EndX - StartX;
1222 dir[1] = EndY - StartY;
1227 double norm = sqrt(ortho[0]*ortho[0] + ortho[1]*ortho[1]);
1229 ortho[0] = 1.0; ortho[1] = 0.0;
1239 for (
float l=
float(-thickness/2.0); l <= float(thickness/2.0); l+=1.0) {
1242 (
unsigned int)(StartX +l * ortho[0]),
1243 (
unsigned int)(StartY +l * ortho[1]),
1245 (
unsigned int)(EndX +l * ortho[0] ),
1246 (
unsigned int)(EndY +l * ortho[1] ),
1254 template <
class StorageType>
1256 double center[2],
double a[2],
1258 const StorageType Value[])
1268 double length_a = sqrt(a[0]*a[0]+a[1]*a[1]);
1269 double length_b = sqrt(b[0]*b[0]+b[1]*b[1]);
1274 double start[2], end[2];
1275 start[0]=center[0]-b[0];
1276 start[1]=center[1]-b[1];
1277 end[0]=center[0]+b[0];
1278 end[1]=center[1]+b[1];
1282 double start[2], end[2];
1283 start[0]=center[0]-a[0];
1284 start[1]=center[1]-a[1];
1285 end[0]=center[0]+a[0];
1286 end[1]=center[1]+a[1];
1292 if ((a[0]*b[0]+a[1]*b[1])/(length_a*length_b)>1e-8){
1293 BIASERR(
"Half axes of ellipse are not perpendicular: ("<<a[0]<<
", "<<a[1]
1294 <<
"), ("<<b[0]<<
", "<<b[1]<<
")");
1295 BIASASSERT((a[0]*b[0]+a[1]*b[1])/(length_a*length_b)<1e-8);
1300 if (length_a>length_b){
1301 dt = atan2(1.0, length_a);
1303 dt = atan2(1.0, length_b);
1308 double ang=atan2(a[1], a[0]);
1311 double ca=cos(ang), sa=sin(ang);
1313 double p[2], rp[2], ap[2];
1319 p[0] = length_a * cos(t);
1320 p[1] = length_b * sin(t);
1326 rp[0] = ap[0]*ca - ap[1]*sa + center[0];
1327 rp[1] = ap[1]*ca + ap[0]*sa + center[1];
1329 ix = (int)rint(rp[0]);
1330 iy = (int)rint(rp[1]);
1331 if (ix>=0 && ix<w && iy>=0 && iy<h){
1332 for (
int i=0; i<cc; i++)
1333 ida[iy][ix*cc+i]=Value[i];
1340 rp[0] = ap[0]*ca - ap[1]*sa + center[0];
1341 rp[1] = ap[1]*ca + ap[0]*sa + center[1];
1343 ix = (int)rint(rp[0]);
1344 iy = (int)rint(rp[1]);
1345 if (ix>=0 && ix<w && iy>=0 && iy<h){
1346 for (
int i=0; i<cc; i++)
1347 ida[iy][ix*cc+i]=Value[i];
1354 rp[0] = ap[0]*ca - ap[1]*sa + center[0];
1355 rp[1] = ap[1]*ca + ap[0]*sa + center[1];
1357 ix = (int)rint(rp[0]);
1358 iy = (int)rint(rp[1]);
1359 if (ix>=0 && ix<w && iy>=0 && iy<h){
1360 for (
int i=0; i<cc; i++)
1361 ida[iy][ix*cc+i]=Value[i];
1368 rp[0] = ap[0]*ca - ap[1]*sa + center[0];
1369 rp[1] = ap[1]*ca + ap[0]*sa + center[1];
1371 ix = (int)rint(rp[0]);
1372 iy = (int)rint(rp[1]);
1373 if (ix>=0 && ix<w && iy>=0 && iy<h){
1374 for (
int i=0; i<cc; i++)
1375 ida[iy][ix*cc+i]=Value[i];
1383 template <
class StorageType>
1385 const std::string & message,
1390 const double hscale,
1391 const double vscale,
1393 const int thickness,
1397 #ifdef BIAS_HAVE_OPENCV
1399 int ret = wrap.
Bind( &dstImg );
1401 BIASWARN(
"Failed to wrap image to IPL to draw text with OpenCV!");
1415 cvPoint(posX, posY),
1417 cvScalar(colorRGB[0], colorRGB[1], colorRGB[2])
1420 BIASWARNONCE(
"Recompile BIAS with OpenCV to enable drawing text!");
1425 template <
class StorageType>
1427 const std::string & message,
1431 const double hscale,
1432 const double vscale,
1434 const int thickness,
1437 #ifdef BIAS_HAVE_IMAGEMAGICKLIB
1440 Magick::InitializeMagick(NULL);
1442 Magick::Image image;
1444 list<Magick::Drawable> drawables;
1447 Magick::DrawableFont fontIM(
"-*-helvetica-medium-r-normal-*-*-120-*-*-*-*-iso8859-1");
1448 drawables.push_back(fontIM);
1449 Magick::ColorRGB color(colorRGB[0], colorRGB[1], colorRGB[2]);
1450 Magick::DrawableStrokeColor stroke(color);
1451 drawables.push_back(stroke);
1452 Magick::DrawableText text(posX,posY,message);
1453 drawables.push_back(text);
1456 #ifdef _GLIBCXX_DEBUG //ImageMagick has incompatible list<> implementation when useing stl debuggin
1457 for (
auto it = drawables.begin(); it != drawables.end(); it++)
1460 image.draw(drawables);
1465 BIASWARNONCE(
"Recompile BIAS with ImageMagick to enable drawing text!");
1470 template <
class StorageType>
1473 const int startY,
const int endX,
const int endY,
1475 const int thickness)
1477 #ifdef BIAS_HAVE_OPENCV
1479 int dx=endX-startX, dy=endY-startY;
1480 if (dx==0 && dy==0){
1490 CvScalar color = cvScalar(colorRGB[0], colorRGB[1], colorRGB[2]);
1491 double angle = atan2( (
double)(start.y - end.y), (
double)(start.x - end.x) );
1495 cvLine(wrap.
p_imgIpl, start, end, color, thickness, CV_AA, shift);
1499 start.x = (int) (end.x + 6 * cos(angle + M_PI / 4));
1500 start.y = (int) (end.y + 6 * sin(angle + M_PI / 4));
1501 cvLine(wrap.
p_imgIpl, start, end, color, thickness, CV_AA, shift);
1503 start.x = (int) (end.x + 6 * cos(angle - M_PI / 4));
1504 start.y = (int) (end.y + 6 * sin(angle - M_PI / 4));
1505 cvLine(wrap.
p_imgIpl, start, end, color, thickness, CV_AA, shift);
1507 BIASWARNONCE(
"Recompile BIAS with OpenCV to enable drawing arrows!");
1511 template <
class StorageType>
1513 const int & centerX,
1514 const int & centerY,
1517 const int & thickness,
1518 const int & linetype,
1522 #ifdef BIAS_HAVE_OPENCV
1525 cvPoint (centerX, centerY),
1527 cvScalar(colorRGB[0], colorRGB[1], colorRGB[2] ),
1533 StorageType color[3] = {colorRGB[0],colorRGB[1],colorRGB[2]};
1534 CircleCenter(dstImg,centerX,centerY,radius,color);
1538 template <
class StorageType>
1545 const int thickness,
1550 #ifdef BIAS_HAVE_OPENCV
1553 cvPoint (pt1X, pt1Y),
1554 cvPoint (pt2X, pt2Y),
1555 cvScalar(colorRGB[0], colorRGB[1], colorRGB[2] ),
1561 StorageType color[3] = {colorRGB[0],colorRGB[1],colorRGB[2]};
1562 InterpolatedLine(dstImg,pt1X,pt1Y,pt2X,pt2Y,color,thickness);
1566 template <
class StorageType>
1573 const int thickness,
1578 #ifdef BIAS_HAVE_OPENCV
1581 cvPoint (pt1X, pt1Y),
1582 cvPoint (pt2X, pt2Y),
1583 cvScalar(colorRGB[0], colorRGB[1], colorRGB[2] ),
1589 StorageType color[3] = {colorRGB[0],colorRGB[1],colorRGB[2]};
1590 RectangleCorners(dstImg,pt1X,pt1Y,pt2X,pt2Y,color);
1594 template <
class StorageType>
1596 const int & centerX,
1597 const int & centerY,
1600 const double & angle,
1601 const double & start_angle,
1602 const double & end_angle,
1604 const int & thickness,
1605 const int & linetype,
1609 #ifdef BIAS_HAVE_OPENCV
1612 cvPoint(centerX, centerY),
1613 cvSize (axesX, axesY),
1617 cvScalar(colorRGB[0], colorRGB[1], colorRGB[2] ),
1622 BIASWARNONCE(
"Recompile BIAS with OpenCV to enable drawing ellipses!");
1632 #define INSTANCE_ImageDraw(type)\
1633 template class BIASImageUtilsBase_EXPORT ImageDraw<type>;
1638 INSTANCE_ImageDraw(
unsigned char)
1639 INSTANCE_ImageDraw(
float)
1640 #ifdef BUILD_IMAGE_INT
1641 INSTANCE_ImageDraw(
int)
1643 #ifdef BUILD_IMAGE_CHAR
1644 INSTANCE_ImageDraw(
char)
1646 #ifdef BUILD_IMAGE_SHORT
1647 INSTANCE_ImageDraw(
short)
1649 #if defined(BUILD_IMAGE_USHORT)
1650 INSTANCE_ImageDraw(
unsigned short)
1652 #ifdef BUILD_IMAGE_DOUBLE
1653 INSTANCE_ImageDraw(
double)
1655 #ifdef BUILD_IMAGE_UINT
1656 INSTANCE_ImageDraw(
unsigned int)
static int InterpolatedLineGrey(Image< StorageType > &im, const int StartX, const int StartY, const int EndX, const int EndY, const StorageType Value, const float thickness=1.0, const float Opacity=1.0)
draws an anti-aliased line that automatically clips to the image borders.
static int Arrow(Image< StorageType > &im, const unsigned start[2], const unsigned end[2], const unsigned length, const unsigned width, const StorageType value[])
draws an arrow from start to end, the tips of the head are length pixel back on the line and width pi...
void Init(int center[2], int radius)
Initialises this BresenhamCircleEighth with new center and radius.
class HomgPoint2D describes a point with 2 degrees of freedom in projective coordinates.
static int RectangleCornersGreyFill(Image< StorageType > &im, const int minx, const int miny, const int maxx, const int maxy, const StorageType GreyValue)
faster for one channel images
static int InterpolatedLine(Image< StorageType > &im, const int StartX, const int StartY, const int EndX, const int EndY, const StorageType Value[], const float thickness=1.0, const float Opacity=1.0)
draws an anti-aliased line that automatically clips to the image borders.
Scans a circle using Bresenham's integer arithmetic algorithm.
static void Circle(BIAS::Image< StorageType > &dstImg, const int ¢erX, const int ¢erY, const int &radius=3, const BIAS::ColourRGB< StorageType > &colorRGB=ColourRGB< StorageType >(255, 255, 255), const int &thickness=1, const int &linetype=8, const int &shift=0)
OpenCV: Draws a circle.
interface class used to ease handover in function calls
static int CircleCenterFilled(Image< StorageType > &im, unsigned int CenterX, unsigned int CenterY, unsigned int Radius, const StorageType Value[])
draws a filled circle using Value
unsigned int GetWidth() const
static int RectangleCorners(Image< StorageType > &im, const int minx, const int miny, const int maxx, const int maxy, const StorageType value[])
rectangles
static StorageType GetContrastValue(StorageType t)
static int CircleCenter(Image< StorageType > &im, unsigned int CenterX, unsigned int CenterY, unsigned int Radius, const StorageType Value[]=NULL)
draws a circular line, either using Value or a good contrast value
static int Line(Image< StorageType > &im, const unsigned int start[2], const unsigned int end[2], const StorageType value[])
lines
static int RectangleCenterGreyFill(Image< StorageType > &im, const int x, const int y, const int size, const StorageType value)
static int Ellipse(Image< StorageType > &im, double center[2], double a[2], double b[2], const StorageType Value[])
draws an ellipse at center with half axes a and b
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
bool GetNext(int next[2])
Returns the coordinate of the next point on the circle.
unsigned int GetHeight() const
bool GetNext(int next[2])
static int LineGrey(Image< StorageType > &im, const unsigned int start[2], const unsigned int end[2], const StorageType value)
faster algorithm for 1 channel images
The image template class for specific storage types.
static int RectangleCenter(Image< StorageType > &im, const int x, const int y, const int size, const StorageType value[])
Draws the rectangle around X, Y with Size and Value[i] in channel i.
bool GetNext(int next[2])
Returns the coordinate of the next point on the 1/8 circle.
void Init(int center[2], int radius)
Initialises this BresenhamCircle with new center and radius.
static int BIAS2ImageMagick(const BIAS::ImageBase &input, Magick::Image &dest)
Returns a new, separate ImageMagick Image for use with ImageMagick created from the source BIAS Image...
Scans a line using Bresenhams integer arithmetic algorithm.
static void Rectangle(BIAS::Image< StorageType > &dstImg, const int &pt1X, const int &pt1Y, const int &pt2X, const int &pt2Y, const BIAS::ColourRGB< StorageType > &colorRGB=ColourRGB< StorageType >(255, 255, 255), const int thickness=1, const int linetype=8, const int shift=0)
OpenCV: Draws a simple, thick or filled rectangle.
static int InterpolatedCircleCenter(Image< StorageType > &im, unsigned int CenterX, unsigned int CenterY, unsigned int Radius, const StorageType Value[], const float Thickness=1.0, const float Opacity=1.0)
draws an anti-aliased circular line that clips automatically to the image borders.
static void TextIM(BIAS::Image< StorageType > &dstImg, const std::string &message, const int &posX=0, const int &posY=20, const ColourRGB< StorageType > &colorRGB=ColourRGB< StorageType >(255, 255, 255), const double hscale=1.0, const double vscale=1.0, const double shear=0, const int thickness=1, const int linetype=8)
ImageMagick: Draw Text into image.
static int ImageMagick2BIAS(Magick::Image &image, BIAS::ImageBase &result)
Returns a new, separate BIAS Image created from the source ImageMagick Image.
wrapper around a BIAS image to be used as an OpenCv IPlimage with shared data area.
Just like BresenhamCircle but only computes 1/8 of the circle.
static int RectangleCenterGrey(Image< StorageType > &im, const int x, const int y, const int size, const StorageType value)
fills the channels with value
void Init(const int start[2], const int end[2])
static void Text(BIAS::Image< StorageType > &dstImg, const std::string &message, const int &posX=0, const int &posY=20, const ColourRGB< StorageType > &colorRGB=ColourRGB< StorageType >(255, 255, 255), const int fontface=1, const double hscale=1.0, const double vscale=1.0, const double shear=0, const int thickness=1, const int linetype=8)
OpenCV: Draw Text into image.
class BIASGeometryBase_EXPORT HomgPoint2D
static int RectangleCornersGrey(Image< StorageType > &im, const int minx, const int miny, const int maxx, const int maxy, const StorageType GreyValue)
faster for one channel images
static int RectangleCornersFill(Image< StorageType > &im, const int minx, const int miny, const int maxx, const int maxy, const StorageType value[])
Draws the filled rectangle defined by upper left and bottom right corner with value[i] in channel i...
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
int Bind(const BIAS::ImageBase *p_src)
create the internal IPL image which shares the data area with the src Bias image. ...