/* This file is part of OpenCV project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at http://opencv.org/license.html. Copyright (C) 2025, Bigvision LLC. This sample demonstrates super-resolution using the SeeMoreDetails model. The model upscales images by 4x while enhancing details and reducing noise. Supports image inputs only. SeeMoreDetails Repo: https://github.com/eduardzamfir/seemoredetails */ #include #include #include #include #include "common.hpp" using namespace cv; using namespace cv::dnn; using namespace std; const int WINDOW_OFFSET_X = 50; const int WINDOW_OFFSET_Y = 50; const int WINDOW_SPACING = 50; const string param_keys = "{ help h | | Print help message }" "{ @alias | seemoredetails | Model alias from models.yml }" "{ zoo | ../dnn/models.yml | Path to models.yml file }" "{ input i | chicky_512.png | Path to input image }" "{ model | | Path to model file }"; const string backend_keys = format( "{ backend | default | Choose one of computation backends: " "default: automatically (by default), " "openvino: Intel's Deep Learning Inference Engine (https://software.intel.com/openvino-toolkit), " "opencv: OpenCV implementation, " "vkcom: VKCOM, " "cuda: CUDA, " "webnn: WebNN }"); const string target_keys = format( "{ target | cpu | Choose one of target computation devices: " "cpu: CPU target (by default), " "opencl: OpenCL, " "opencl_fp16: OpenCL fp16 (half-float precision), " "vpu: VPU, " "vulkan: Vulkan, " "cuda: CUDA, " "cuda_fp16: CUDA fp16 (half-float preprocess) }"); static Mat postprocessOutput(const Mat &output, const Size &originalSize) { Mat squeezed; if (output.dims == 4 && output.size[0] == 1) { vector newShape = {output.size[1], output.size[2], output.size[3]}; squeezed = output.reshape(0, newShape); } else { squeezed = output.clone(); } Mat outputImage; vector channels(3); for (int i = 0; i < 3; i++) { channels[2-i] = Mat(squeezed.size[1], squeezed.size[2], CV_32F, squeezed.ptr(i)); } merge(channels, outputImage); outputImage = max(0.0, min(1.0, outputImage)); outputImage.convertTo(outputImage, CV_8UC3, 255.0); Size targetSize(originalSize.width * 4, originalSize.height * 4); Mat result; resize(outputImage, result, targetSize); return result; } static Mat applySuperResolution(Net &net, const Mat &image, float scale, const Scalar &mean, bool swapRB, int width, int height) { Mat blob = blobFromImage(image, scale, Size(width, height), mean, swapRB, false, CV_32F); net.setInput(blob); Mat output; net.forward(output); return postprocessOutput(output, Size(image.cols, image.rows)); } static double calculateFontScale(const Mat &image) { double baseScale = min(image.cols, image.rows) / 800.0; return max(0.5, baseScale); } static void processFrame(Net &net, Mat &frame, float scale, const Scalar &mean, bool swapRB, int width, int height) { Mat result = applySuperResolution(net, frame, scale, mean, swapRB, width, height); double fontScale = calculateFontScale(frame); int thickness = max(1, (int)(fontScale * 2)); putText(frame, "Original", Point(10, 30), FONT_HERSHEY_SIMPLEX, fontScale, Scalar(0, 255, 0), thickness); double resultFontScale = calculateFontScale(result); int resultThickness = max(1, (int)(resultFontScale * 2)); putText(result, "Super-Resolution 4x", Point(20, 50), FONT_HERSHEY_SIMPLEX, resultFontScale, Scalar(0, 255, 0), resultThickness); imshow("Input", frame); imshow("Super-Resolution", result); } int main(int argc, char **argv) { const string about = "This sample demonstrates super-resolution using the SeeMore model.\n" "The model upscales images by 4x while enhancing details.\n\n" "Usage examples:\n" "\t./super_resolution\n" "\t./super_resolution --input=image.jpg\n" "\t./super_resolution --input=../data/chicky_512.png\n"; string keys = param_keys + backend_keys + target_keys; CommandLineParser parser(argc, argv, keys); if (parser.has("help")) { cout << about << endl; parser.printMessage(); return 0; } string modelName = parser.get("@alias"); string zooFile = samples::findFile(parser.get("zoo")); keys += genPreprocArguments(modelName, zooFile); parser = CommandLineParser(argc, argv, keys); float scale = parser.get("scale"); Scalar mean = parser.get("mean"); bool swapRB = parser.get("rgb"); String backend = parser.get("backend"); String target = parser.get("target"); String sha1 = parser.get("sha1"); string model = findModel(parser.get("model"), sha1); int width = parser.get("width"); int height = parser.get("height"); string inputPath = findFile(parser.get("input")); if (model.empty()) { cerr << "Model file not found" << endl; return -1; } Net net; try { net = readNetFromONNX(model); net.setPreferableBackend(getBackendID(backend)); net.setPreferableTarget(getTargetID(target)); } catch (const Exception &e) { cerr << "Error loading model: " << e.what() << endl; return -1; } Mat testImage = imread(inputPath); if (testImage.empty()) { cerr << "Cannot load image: " << inputPath << endl; return -1; } namedWindow("Input", WINDOW_NORMAL); namedWindow("Super-Resolution", WINDOW_NORMAL); moveWindow("Input", WINDOW_OFFSET_X, WINDOW_OFFSET_Y); moveWindow("Super-Resolution", WINDOW_OFFSET_X + testImage.cols + WINDOW_SPACING, WINDOW_OFFSET_Y); processFrame(net, testImage, scale, mean, swapRB, width, height); waitKey(0); destroyAllWindows(); return 0; }