pythoncpython

Suppress stdout message from C/C++ library


I am attempting to suppress a message that is printed to stdout by a library implemented in C.

My specific usecase is OpenCV, so I will use it for the MCVE below. The estimateChessboardSharpness function has a printout when the grid size is too small (which happens here). I made a PR to fix it, but in the meantime, I'd like to suppress the message. For example:

import cv2
import numpy as np

img = np.zeros((512, 640), dtype='uint8')
corners = []
for i in range(10):
    for j in range(8):
        corner = (30 + 3 * j, 70 + 3 * i)
        if i and j:
            corners.append(corner)
        if (i % 2) ^ (j % 2):
            img[corner[0]:corner[0] + 3, corner[1]:corner[1] + 3] = 255
corners = np.array(corners)
>>> cv2.estimateChessboardSharpness(img, (9, 7), corners)
calcEdgeSharpness: checkerboard too small for calculation.
((9999.0, 9999.0, 9999.0, 9999.0), None)

The line appears to be a simple std::cout << ..., so I have tried all of the following:

from contextlib import redirect_stdout
from os imoprt devnull
import sys

with redirect_stdout(None):
    cv2.estimateChessboardSharpness(img, (9, 7), corners)

with open(devnull, "w") as null, redirect_stdout(null):
    cv2.estimateChessboardSharpness(img, (9, 7), corners)

sys.stdout = open(devnull, "w")
cv2.estimateChessboardSharpness(img, (9, 7), corners)

I've even tried redirect_stderr instead of redirect_stdout just in case. I've also tried setting OPENCV_LOG_LEVEL=SILENT in bash and os.environ["OPENCV_LOG_LEVEL"] = "SILENT" in python before importing cv2, not that I expected stdout to be conflated with logging in this case.

In all cases, the message prints. How do I make it stop?


Solution

  • Assuming a UNIX-like platform, (you'll get an OSError if not)

    You can save the underlying fd with

    backup = os.dup(sys.stdout.fileno())
    

    point it to a different file (eg. different) with

    os.dup2(different.fileno(), sys.stdout.fileno())
    

    and resume normal service with

    os.dup2(backup, sys.stdout.fileno())
    

    Do note that this won't behave at all nicely if the file you redirect to is also being used for buffered output (ie, you have writes to different mixed with C++ library writes to std::cout which is using different.fileno()...)