Tag Archives: C++

C++ Schnelleinstieg

English summary: I have published a C++ beginners book. As it is in German, so is this post.

Auf 304 kompakten Seiten bekommen Sie einen fundierten Einstieg in die C++ Programmierung. Besonders hervorzuheben und für ein Einsteigerbuch ungewöhnlich ist die Einbindung von diversen Open-Source-Bibliotheken – professionell gemanaged mittels des Paketmanagers vcpkg. Im Rahmen des Buches erlernen Sie auch fortgeschrittene Fähigkeiten wie die Programmierung graphischer Oberflächen und das Arbeiten mit Web-APIs, wie der von Wikipedia. Das Buch legt wert auf einen verständlichen aber dennoch professionellen Programmierstil und gibt einen Ausblick über das Programmieren im professionellen Umfeld, sowie Anküpfungspunkte zum selbstständigen Erweitern der eigenen Kenntnisse.

Das Begleitmaterial sowie das Inhaltsverzeichnis und eine Leseprobe finden Sie auf https://cpp.hasper.info/

Beim Verlag kaufen: C++ Schnelleinstieg

Bei Amazon kaufen: C++ Schnelleinstieg

Natürlich freue ich mich sehr über eine Bewertung des Buches.

Buchcover C++ Schnelleinstieg, Philipp Hasper
ISBN: 9783747503225
  • Alle Grundlagen einfach erläutert
  • Objektorientierte Programmierung
  • Einsatz von Open-Source-Bibliotheken
  • Grafische Benutzungsoberflächen (GUI)
  • Internetanfragen und JSON-Parsing
  • Zeiger und virtuelle Methoden
  • Fehlersuche und Debugging
  • Moderner Programmierstil
  • Programmcode, Lösungen und Glossar zum Download

»Während viele andere C++-Lehrbücher ihr Heil in der Erklärung jedes noch so obskuren Details suchen, fokussiert sich Hasper auf alles Wichtige, das Entwicklerinnen und Entwickler bei der alltäglichen Arbeit brauchen. Haben sie bisher mit Sprachen wie JavaScript oder C# Erfahrung gesammelt, findet sich hier ein hilfreicher Wegweiser durch den Dschungel des modernen C++.«

(Heise Online, 09/2021)

»Didaktisch gut aufgebaut.«

(ekz Bibliotheksservice, 10/2021)

Worry-free text writing into OpenCV images

Using cv::putText is cumbersome and placing your text at the correct position with the correct size is hard. Here is a wrapper function dealing with all of this for you. The text is fitted inside the given image, even multiple lines are possible and everything is nicely centered.

void ioxp::putText(cv::Mat imgROI, const std::string &text, const int fontFace = cv::FONT_HERSHEY_PLAIN,
    const cv::Scalar color = cv::Scalar::all(255), const int thickness = 1, const int lineType = cv::LINE_8)
{
    /*
     * Split the given text into its lines
     */
    std::vector<std::string> textLines;
    std::istringstream f(text);
    std::string s;
    while (std::getline(f, s, '\n')) {
        textLines.push_back(s);
    }

    /*
     * Calculate the line sizes and overall bounding box
     */
    std::vector<cv::Size> textLineSizes;
    cv::Size boundingBox(0,0);
    int baseline = 0;
    for (std::string line : textLines) {
        cv::Size lineSize = cv::getTextSize(line, fontFace, 1, thickness, &baseline);
        baseline += 2 * thickness;
        lineSize.width += 2 * thickness;
        lineSize.height += baseline;
        textLineSizes.push_back(lineSize);
        boundingBox.width = std::max(boundingBox.width, lineSize.width);
        boundingBox.height += lineSize.height;
    }

    const double scale = std::min(imgROI.rows / static_cast<double>(boundingBox.height),
                                  imgROI.cols / static_cast<double>(boundingBox.width));
    boundingBox.width *= scale;
    boundingBox.height *= scale;
    baseline *= scale;
    for (size_t i = 0; i < textLineSizes.size(); i++) {
        textLineSizes.at(i).width *= scale;
        textLineSizes.at(i).height *= scale;
    }
    /*
     * Draw the text line-by-line
     */
    int y = (imgROI.rows - boundingBox.height + baseline) / 2;
    for (size_t i = 0; i < textLines.size(); i++) {
        y += textLineSizes.at(i).height;
        // center the text horizontally
        cv::Point textOrg((imgROI.cols - textLineSizes.at(i).width) / 2, y - baseline);
        cv::putText(imgROI, textLines.at(i), textOrg, fontFace, scale, color, thickness, lineType);
    }
}

This is how you use it and how the results look like:

    cv::Mat outputImage(360, 640, CV_8UC3);
    outputImage.setTo(0);
    ioxp::putText(outputImage, "Short text");
    cv::imshow("text", outputImage);
    cv::waitKey(0);

    cv::Mat outputImage(360, 640, CV_8UC3);
    outputImage.setTo(0);
    ioxp::putText(outputImage,
      "Some longer text, even with\nmultiple lines spread over the whole image");
    cv::imshow("text", outputImage);
    cv::waitKey(0);

    cv::Mat outputImage(360, 640, CV_8UC3);
    outputImage.setTo(0);
    ioxp::putText(outputImage, "\n\n\nEmpty\n\n\nLines\n\n\n");
    cv::imshow("text", outputImage);
    cv::waitKey(0);

By using the Rectangle accessor you can define exactly, which part of the image the text should be placed in:

    cv::Mat outputImage(360, 640, CV_8UC3);
    outputImage.setTo(0);
    ioxp::putText(outputImage(cv::Rect(0, outputImage.rows / 10, outputImage.cols, outputImage.rows / 10)),
      "Text placed in the upper\n10 percent of the image");
    cv::imshow("text", outputImage);
    cv::waitKey(0);

War stories: When the visual debugger fails you

I recently had a very strange crash and after some digging I found the lines I suspected the bug to lurk around. They looked something like this:

    const std::string contents = readFile("myFile.txt");
    const std::vector<std::string> lines = utils::split(contents, "\n");
    for (std::string line : lines) {
        if (line.empty()) {
            continue;
        }
        //...
        // Do something elaborate with the line, e.g. printing to console
        std::cout << "<line>" << line.c_str() << "</line>" << std::endl;
    }

The crash occurred in the //... lines because the line was not empty. Wait – what? I tested for emptiness before!
Opening the debugger revealed the following strange situation:

and the above small sample file prints on my (Windows) console:

<line>First line</line>
<line>third line (second one is empty)</line>
<line>fourth line</line>
<line></line>

Scrolling trough the commit history, the problem turned out to be introduced with this change:
OLD CODE (working):

std::string readFile(const std::string& fname, bool binaryMode = false)
{
    std::ios_base::openmode mode = std::ios_base::in;
    if (binaryMode)
        mode |= std::ios_base::binary;

    std::ifstream ifs(fname, mode);
    if (!ifs) {
        throw std::exception(("Couldn't open file: " + fname).c_str());
    }
    return std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
}

NEW CODE (not working):

std::string readFile(const std::string& fname, bool binaryMode = false)
{
    std::ios_base::openmode mode = std::ios_base::in;
    if (binaryMode) {
        mode |= std::ios_base::binary;
    }

    std::ifstream in(fname, mode);
    if (!in) {
        throw std::exception(("Couldn't open file: " + fname).c_str());
    }

    // Used C++ style reading which is more efficient than using stream buffer iterators
    // http://insanecoding.blogspot.de/2011/11/how-to-read-in-file-in-c.html
    std::string contents;
    in.seekg(0, std::ios::end);
    contents.resize(in.tellg());
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], contents.size());
    in.close();

    return contents;
}

The problem was that reading the file with the more efficient solution resulted in the string having a bunch of null terminators if the file contained a new-line in the end. Obviously, .empty() returns false, so the check passed. As a side note: to simulate my crash bug by showing an unexpected console output, I had to pipe the C-string. When piping the C++ string, the line is printed with some whitespaces.

This is how I fixed it:

std::string readFile(const std::string& fname, bool binaryMode = false)
{
    std::ios_base::openmode mode = std::ios_base::in;
    if (binaryMode) {
        mode |= std::ios_base::binary;
    }

    std::ifstream in(fname, mode);
    if (!in) {
        throw std::exception(("Couldn't open file: " + fname).c_str());
    }

    // Used C++ style reading which is more efficient than using stream buffer iterators
    // http://insanecoding.blogspot.de/2011/11/how-to-read-in-file-in-c.html
    std::string contents;
    in.seekg(0, std::ios::end);
    contents.resize(in.tellg());
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], contents.size());
    in.close();

    if (binaryMode) {
        return contents;
    }
    else {
        // Depending on the file, the last line might contain one or more \0 control characters. Remove them
        return contents.erase(contents.find_last_not_of('\0') + 1);
    }
}

Migrating Eigen2 to Eigen3: useful regular expressions

I’ve recently migrated a project from Eigen2 library to Eigen3 based on the very useful staged migration path.

Here are two regular expressions which came in really handy. Of course you have to manually check the result but they save a lot of time.

/*
 * Using the new linear solver interface
 */

// Regular expression for finding
([^\S\n]*)([^\s]*)\.solve\(([\s]*)(.*?)([\s]*),([\s]*)\&(.*?)([\s]*)\)\;
// Regular expression for replacing
$1$7 = $2.solve\($4\);

Live-Preview

/*
 * Use the static way for map creation.
 * Does not work with all types
 */

// Regular expression for finding
Eigen::Map<(.*?)>\(
// Regular expression for replacing
$1::Map\(

Live-Preview