4

Note: This question How to put text into a bounding box in OpenCV? is in some ways similar to this one but it is not the same question. The OP of the questions tried to spread a text to the whole size of his image & the code in the answer that gots the mark is just resizing the text using a mask.

I'm using openCV combined with C++ to do some image detection & manipulation.

So I want to align a text with a unknown length at a specific origin. The font-scale should be calculated because I'd like to specify a width factor for the maximum Text-width like you can see in the image below:

![enter image description here

This is the code I got so far:

int fontFace = cv::FONT_HERSHEY_DUPLEX,
    fontScale = myTextString.size() / 10;

cv::Size textSize = getTextSize(image, fontFace, fontScale, 0, 0);
putText(image, myTextString, cv::Point( (origin.x + textSize.width)/2, (origin.y + textSize.height)/2 ), fontFace, fontScale, Scalar(255, 0, 0));
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • **The question:** How to implement a function that calculates the scale factor of a **Text** for a maximum width related to the length of text? | **problem:** really got no idea how to go on to solve the problem. –  May 15 '18 at 15:38
  • So you want to select a `fontScale` such that the `textWidth` does not exceed the `maximumWidth`. Is this right? – zindarod May 15 '18 at 16:35
  • You got it right :) @zindarod –  May 15 '18 at 16:42
  • Have you seen [this answer](https://stackoverflow.com/q/4902198/2286337)? – zindarod May 15 '18 at 17:20
  • 1
    **Python Imaging Library version** `vs` **openCV**. I think you mixed something up :) @zindarod –  May 15 '18 at 17:28
  • You were supposed to get the general algorithm, iteratively compute `fontScale` until it matches your criteria. Don't wait for free lunch dude. – zindarod May 15 '18 at 17:50

1 Answers1

4

Something like this should do it. You can change how the margins are calculated to change the horizontal/vertical alignment of the font.

If the height doesn't matter, you can just leave target.height a large number.

void drawtorect(cv::Mat & mat, cv::Rect target, int face, int thickness, cv::Scalar color, const std::string & str)
{
    cv::Size rect = cv::getTextSize(str, face, 1.0, thickness, 0);
    double scalex = (double)target.width / (double)rect.width;
    double scaley = (double)target.height / (double)rect.height;
    double scale = std::min(scalex, scaley);
    int marginx = scale == scalex ? 0 : (int)((double)target.width * (scalex - scale) / scalex * 0.5);
    int marginy = scale == scaley ? 0 : (int)((double)target.height * (scaley - scale) / scaley * 0.5);
    cv::putText(mat, str, cv::Point(target.x + marginx, target.y + target.height - marginy), face, scale, color, thickness, 8, false);
}

* edit *

// Sample code
int L = 80; // width and height per square
int M = 60;
cv::Mat m( 5*M, 7*L,CV_8UC3,cv::Scalar(0,0,0) );
// create checkerboard
for ( int y=0,ymax=m.rows-M;y<=ymax; y+=M)
{
    int c = (y/M)%2 == 0 ? 0 : 1;
    for ( int x=0,xmax=m.cols-L;x<=xmax;x+=L)
    {
        if ( (c++)%2!=0 )
            continue; // skip odd squares
        // convenient way to do this
        m( cv::Rect(x,y,L,M) ).setTo( cv::Scalar(64,64,64) );
    }
}
// fill checkerboard ROIs by some text
int64 id=1;
for ( int y=0,ymax=m.rows-M;y<=ymax; y+=M)
{
    for ( int x=0,xmax=m.cols-L;x<=xmax;x+=L)
    {
        std::stringstream ss;
        ss<<(id<<=1); // some increasing text input
        drawtorect( m, cv::Rect(x,y,L,M), cv::FONT_HERSHEY_PLAIN,1,cv::Scalar(255,255,255),ss.str() );
    }
}

enter image description here

mainactual
  • 1,625
  • 14
  • 17