vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:11:13 +08:00
commit 12022378a3
3872 changed files with 2513409 additions and 0 deletions
@@ -0,0 +1,73 @@
#include "opencv2/xphoto.hpp"
#include "opencv2/highgui.hpp"
const char* keys =
{
"{i || input image name}"
"{o || output image name}"
"{sigma || expected noise standard deviation}"
"{tw |4| template window size}"
"{sw |16| search window size}"
};
int main(int argc, const char** argv)
{
bool printHelp = (argc == 1);
printHelp = printHelp || (argc == 2 && std::string(argv[1]) == "--help");
printHelp = printHelp || (argc == 2 && std::string(argv[1]) == "-h");
if (printHelp)
{
printf("\nThis sample demonstrates BM3D image denoising\n"
"Call:\n"
" bm3d_image_denoising -i=<string> -sigma=<double> -tw=<int> -sw=<int> [-o=<string>]\n\n");
return 0;
}
cv::CommandLineParser parser(argc, argv, keys);
if (!parser.check())
{
parser.printErrors();
return -1;
}
std::string inFilename = parser.get<std::string>("i");
std::string outFilename = parser.get<std::string>("o");
cv::Mat src = cv::imread(inFilename, cv::IMREAD_GRAYSCALE);
if (src.empty())
{
printf("Cannot read image file: %s\n", inFilename.c_str());
return -1;
}
float sigma = parser.get<float>("sigma");
if (sigma == 0.0)
sigma = 15.0;
int templateWindowSize = parser.get<int>("tw");
if (templateWindowSize == 0)
templateWindowSize = 4;
int searchWindowSize = parser.get<int>("sw");
if (searchWindowSize == 0)
searchWindowSize = 16;
cv::Mat res(src.size(), src.type());
cv::xphoto::bm3dDenoising(src, res, sigma, templateWindowSize, searchWindowSize);
if (outFilename.empty())
{
cv::namedWindow("input image", cv::WINDOW_NORMAL);
cv::imshow("input image", src);
cv::namedWindow("denoising result", cv::WINDOW_NORMAL);
cv::imshow("denoising result", res);
cv::waitKey(0);
}
else
{
cv::imwrite(outFilename, res);
}
return 0;
}
+68
View File
@@ -0,0 +1,68 @@
#include "opencv2/xphoto.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
using namespace std;
const char *keys = { "{help h usage ? | | print this message}"
"{i | | input image name }"
"{o | | output image name }"
"{a |grayworld| color balance algorithm (simple, grayworld or learning_based)}"
"{m | | path to the model for the learning-based algorithm (optional) }" };
int main(int argc, const char **argv)
{
CommandLineParser parser(argc, argv, keys);
parser.about("OpenCV color balance demonstration sample");
if (parser.has("help") || argc < 2)
{
parser.printMessage();
return 0;
}
string inFilename = parser.get<string>("i");
string outFilename = parser.get<string>("o");
string algorithm = parser.get<string>("a");
string modelFilename = parser.get<string>("m");
if (!parser.check())
{
parser.printErrors();
return -1;
}
Mat src = imread(inFilename, 1);
if (src.empty())
{
printf("Cannot read image file: %s\n", inFilename.c_str());
return -1;
}
Mat res;
Ptr<xphoto::WhiteBalancer> wb;
if (algorithm == "simple")
wb = xphoto::createSimpleWB();
else if (algorithm == "grayworld")
wb = xphoto::createGrayworldWB();
else if (algorithm == "learning_based")
wb = xphoto::createLearningBasedWB(modelFilename);
else
{
printf("Unsupported algorithm: %s\n", algorithm.c_str());
return -1;
}
wb->balanceWhite(src, res);
if (outFilename == "")
{
namedWindow("after white balance", 1);
imshow("after white balance", res);
waitKey(0);
}
else
imwrite(outFilename, res);
return 0;
}
@@ -0,0 +1,268 @@
#!/usr/bin/env python
from __future__ import print_function
import os, sys, argparse, json
import numpy as np
import scipy.io
import cv2 as cv
import timeit
from learn_color_balance import load_ground_truth
def load_json(path):
f = open(path, "r")
data = json.load(f)
return data
def save_json(obj, path):
tmp_file = path + ".bak"
f = open(tmp_file, "w")
json.dump(obj, f, indent=2)
f.flush()
os.fsync(f.fileno())
f.close()
try:
os.rename(tmp_file, path)
except:
os.remove(path)
os.rename(tmp_file, path)
def parse_sequence(input_str):
if len(input_str) == 0:
return []
else:
return [o.strip() for o in input_str.split(",") if o]
def stretch_to_8bit(arr, clip_percentile = 2.5):
arr = np.clip(arr * (255.0 / np.percentile(arr, 100 - clip_percentile)), 0, 255)
return arr.astype(np.uint8)
def evaluate(im, algo, gt_illuminant, i, range_thresh, bin_num, dst_folder, model_folder):
new_im = None
start_time = timeit.default_timer()
if algo=="grayworld":
inst = cv.xphoto.createGrayworldWB()
inst.setSaturationThreshold(0.95)
new_im = inst.balanceWhite(im)
elif algo=="nothing":
new_im = im
elif algo.split(":")[0]=="learning_based":
model_path = ""
if len(algo.split(":"))>1:
model_path = os.path.join(model_folder, algo.split(":")[1])
inst = cv.xphoto.createLearningBasedWB(model_path)
inst.setRangeMaxVal(range_thresh)
inst.setSaturationThreshold(0.98)
inst.setHistBinNum(bin_num)
new_im = inst.balanceWhite(im)
elif algo=="GT":
gains = gt_illuminant / min(gt_illuminant)
g1 = float(1.0 / gains[2])
g2 = float(1.0 / gains[1])
g3 = float(1.0 / gains[0])
new_im = cv.xphoto.applyChannelGains(im, g1, g2, g3)
time = 1000*(timeit.default_timer() - start_time) #time in ms
if len(dst_folder)>0:
if not os.path.exists(dst_folder):
os.makedirs(dst_folder)
im_name = ("%04d_" % i) + algo.replace(":","_") + ".jpg"
cv.imwrite(os.path.join(dst_folder, im_name), stretch_to_8bit(new_im))
#recover the illuminant from the color balancing result, assuming the standard model:
estimated_illuminant = [0, 0, 0]
eps = 0.01
estimated_illuminant[2] = np.percentile((im[:,:,0] + eps) / (new_im[:,:,0] + eps), 50)
estimated_illuminant[1] = np.percentile((im[:,:,1] + eps) / (new_im[:,:,1] + eps), 50)
estimated_illuminant[0] = np.percentile((im[:,:,2] + eps) / (new_im[:,:,2] + eps), 50)
res = np.arccos(np.dot(gt_illuminant,estimated_illuminant)/
(np.linalg.norm(gt_illuminant) * np.linalg.norm(estimated_illuminant)))
return (time, (res / np.pi) * 180)
def build_html_table(out, state, stat_list, img_range):
stat_dict = {'mean': ('Mean error', lambda arr: np.mean(arr)),
'median': ('Median error',lambda arr: np.percentile(arr, 50)),
'p05': ('5<sup>th</sup> percentile',lambda arr: np.percentile(arr, 5)),
'p20': ('20<sup>th</sup> percentile',lambda arr: np.percentile(arr, 20)),
'p80': ('80<sup>th</sup> percentile',lambda arr: np.percentile(arr, 80)),
'p95': ('95<sup>th</sup> percentile',lambda arr: np.percentile(arr, 95))
}
html_out = ['<style type="text/css">\n',
' html, body {font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;}\n',
' .tbl{background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:"Lucida Sans Unicode","Lucida Grande",Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;}\n',
' .tbl span{display:block;white-space:nowrap;}\n',
' .tbl thead tr:last-child th {padding-bottom:5px;}\n',
' .tbl tbody tr:first-child td {border-top:3px solid #6678B1;}\n',
' .tbl th{border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;}\n',
' .tbl td{border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;}\n',
' .tbl tbody tr:hover td{color:#000099;}\n',
' .tbl caption{font:italic 16px "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;}\n',
' .firstingroup {border-top:2px solid #6678B1;}\n',
'</style>\n\n']
html_out += ['<table class="tbl">\n',
' <thead>\n',
' <tr>\n',
' <th align="center" valign="top"> Algorithm Name </th>\n',
' <th align="center" valign="top"> Average Time </th>\n']
for stat in stat_list:
if stat not in stat_dict.keys():
print("Error: unsupported statistic " + stat)
sys.exit(1)
html_out += [' <th align="center" valign="top"> ' +
stat_dict[stat][0] +
' </th>\n']
html_out += [' </tr>\n',
' </thead>\n',
' <tbody>\n']
for algorithm in state.keys():
arr = [state[algorithm][file]["angular_error"] for file in state[algorithm].keys() if file>=img_range[0] and file<=img_range[1]]
average_time = "%.2f ms" % np.mean([state[algorithm][file]["time"] for file in state[algorithm].keys()
if file>=img_range[0] and file<=img_range[1]])
html_out += [' <tr>\n',
' <td>' + algorithm + '</td>\n',
' <td>' + average_time + '</td>\n']
for stat in stat_list:
html_out += [' <td> ' +
"%.2f&deg" % stat_dict[stat][1](arr) +
' </td>\n']
html_out += [' </tr>\n']
html_out += [' </tbody>\n',
'</table>\n']
f = open(out, 'w')
f.writelines(html_out)
f.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=("A benchmarking script for color balance algorithms"),
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"-a",
"--algorithms",
metavar="ALGORITHMS",
default="",
help=("Comma-separated list of color balance algorithms to evaluate. "
"Currently available: GT,learning_based,grayworld,nothing. "
"Use a colon to set a specific model for the learning-based "
"algorithm, e.g. learning_based:model1.yml,learning_based:model2.yml"))
parser.add_argument(
"-i",
"--input_folder",
metavar="INPUT_FOLDER",
default="",
help=("Folder containing input images to evaluate on. Assumes minimally "
"processed png images like in the Gehler-Shi (http://www.cs.sfu.ca/~colour/data/shi_gehler/) "
"or NUS 8-camera (http://www.comp.nus.edu.sg/~whitebal/illuminant/illuminant.html) datasets"))
parser.add_argument(
"-g",
"--ground_truth",
metavar="GROUND_TRUTH",
default="real_illum_568..mat",
help=("Path to the mat file containing ground truth illuminations. Currently "
"supports formats supplied by the Gehler-Shi and NUS 8-camera datasets."))
parser.add_argument(
"-o",
"--out",
metavar="OUT",
default="./white_balance_eval_result.html",
help="Path to the output html table")
parser.add_argument(
"-s",
"--state",
metavar="STATE_JSON",
default="./WB_evaluation_state.json",
help=("Path to a json file that stores the current evaluation state"))
parser.add_argument(
"-t",
"--stats",
metavar="STATS",
default="mean,median,p05,p20,p80,p95",
help=("Comma-separated list of error statistics to compute and list "
"in the output table. All the available ones are used by default"))
parser.add_argument(
"-b",
"--input_bit_depth",
metavar="INPUT_BIT_DEPTH",
default="",
help=("Assumed bit depth for input images. Should be specified in order to "
"use full bit depth for evaluation (for instance, -b 12 for 12 bit images). "
"Otherwise, input images are converted to 8 bit prior to the evaluation."))
parser.add_argument(
"-d",
"--dst_folder",
metavar="DST_FOLDER",
default="",
help=("If specified, this folder will be used to store the color correction results"))
parser.add_argument(
"-r",
"--range",
metavar="RANGE",
default="0,0",
help=("Comma-separated range of images from the dataset to evaluate on (for instance: 0,568). "
"All available images are used by default."))
parser.add_argument(
"-m",
"--model_folder",
metavar="MODEL_FOLDER",
default="",
help=("Path to the folder containing models for the learning-based color balance algorithm (optional)"))
args, other_args = parser.parse_known_args()
if not os.path.exists(args.input_folder):
print("Error: " + args.input_folder + (" does not exist. Please, correctly "
"specify the -i parameter"))
sys.exit(1)
if not os.path.exists(args.ground_truth):
print("Error: " + args.ground_truth + (" does not exist. Please, correctly "
"specify the -g parameter"))
sys.exit(1)
state = {}
if os.path.isfile(args.state):
state = load_json(args.state)
algorithm_list = parse_sequence(args.algorithms)
img_range = list(map(int, parse_sequence(args.range)))
if len(img_range)!=2:
print("Error: Please specify the -r parameter in form <first_image_index>,<last_image_index>")
sys.exit(1)
img_files = sorted(os.listdir(args.input_folder))
(gt_illuminants,black_levels) = load_ground_truth(args.ground_truth)
for algorithm in algorithm_list:
i = 0
if algorithm not in state.keys():
state[algorithm] = {}
sz = len(img_files)
for file in img_files:
if file not in state[algorithm].keys() and\
((i>=img_range[0] and i<img_range[1]) or img_range[0]==img_range[1]==0):
cur_path = os.path.join(args.input_folder, file)
im = cv.imread(cur_path, -1).astype(np.float32)
im -= black_levels[i]
range_thresh = 255
if len(args.input_bit_depth)>0:
range_thresh = 2**int(args.input_bit_depth) - 1
im = np.clip(im, 0, range_thresh).astype(np.uint16)
else:
im = stretch_to_8bit(im)
(time,angular_err) = evaluate(im, algorithm, gt_illuminants[i], i, range_thresh,
256 if range_thresh > 255 else 64, args.dst_folder, args.model_folder)
state[algorithm][file] = {"angular_error": angular_err, "time": time}
sys.stdout.write("Algorithm: %-20s Done: [%3d/%3d]\r" % (algorithm, i, sz)),
sys.stdout.flush()
save_json(state, args.state)
i+=1
save_json(state, args.state)
build_html_table(args.out, state, parse_sequence(args.stats), [img_files[img_range[0]], img_files[img_range[1]-1]])
@@ -0,0 +1,69 @@
#include "opencv2/xphoto.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/utility.hpp"
const char* keys =
{
"{i || input image name}"
"{o || output image name}"
"{sigma || expected noise standard deviation}"
"{psize |16| expected noise standard deviation}"
};
int main( int argc, const char** argv )
{
bool printHelp = ( argc == 1 );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "--help" );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "-h" );
if ( printHelp )
{
printf("\nThis sample demonstrates dct-based image denoising\n"
"Call:\n"
" dct_image_denoising -i=<string> -sigma=<double> -psize=<int> [-o=<string>]\n\n");
return 0;
}
cv::CommandLineParser parser(argc, argv, keys);
if ( !parser.check() )
{
parser.printErrors();
return -1;
}
std::string inFilename = parser.get<std::string>("i");
std::string outFilename = parser.get<std::string>("o");
cv::Mat src = cv::imread(inFilename, 1);
if ( src.empty() )
{
printf("Cannot read image file: %s\n", inFilename.c_str());
return -1;
}
double sigma = parser.get<double>("sigma");
if (sigma == 0.0)
sigma = 15.0;
int psize = parser.get<int>("psize");
if (psize == 0)
psize = 16;
cv::Mat res(src.size(), src.type());
cv::xphoto::dctDenoising(src, res, sigma, psize);
if ( outFilename == "" )
{
cv::namedWindow("denoising result", 1);
cv::imshow("denoising result", res);
cv::waitKey(0);
}
else
cv::imwrite(outFilename, res);
return 0;
}
+78
View File
@@ -0,0 +1,78 @@
#include "opencv2/xphoto.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <ctime>
#include <iostream>
const char* keys =
{
"{i || input image name}"
"{m || mask image name}"
"{o || output image name}"
};
int main( int argc, const char** argv )
{
bool printHelp = ( argc == 1 );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "--help" );
printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "-h" );
if ( printHelp )
{
printf("\nThis sample demonstrates shift-map image inpainting\n"
"Call:\n"
" inpainting -i=<string> -m=<string> [-o=<string>]\n\n");
return 0;
}
cv::CommandLineParser parser(argc, argv, keys);
if ( !parser.check() )
{
parser.printErrors();
return -1;
}
std::string inFilename = parser.get<std::string>("i");
std::string maskFilename = parser.get<std::string>("m");
std::string outFilename = parser.get<std::string>("o");
cv::Mat src = cv::imread(inFilename, cv::IMREAD_UNCHANGED);
if ( src.empty() )
{
printf( "Cannot read image file: %s\n", inFilename.c_str() );
return -1;
}
cv::cvtColor(src, src, cv::COLOR_BGR2Lab);
cv::Mat mask = cv::imread(maskFilename, cv::IMREAD_GRAYSCALE);
if ( mask.empty() )
{
printf( "Cannot read image file: %s\n", maskFilename.c_str() );
return -1;
}
cv::threshold(mask, mask, 128, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
cv::Mat res(src.size(), src.type());
int time = clock();
cv::xphoto::inpaint( src, mask, res, cv::xphoto::INPAINT_SHIFTMAP );
std::cout << "time = " << (clock() - time)
/ double(CLOCKS_PER_SEC) << std::endl;
cv::cvtColor(res, res, cv::COLOR_Lab2BGR);
if ( outFilename == "" )
{
cv::namedWindow("inpainting result", 1);
cv::imshow("inpainting result", res);
cv::waitKey(0);
}
else
cv::imwrite(outFilename, res);
return 0;
}
@@ -0,0 +1,290 @@
#!/usr/bin/env python
from __future__ import print_function
import os, sys, argparse
import numpy as np
import scipy.io
from sklearn.tree import DecisionTreeRegressor
import cv2 as cv
import random
def parse_sequence(input_str):
if len(input_str) == 0:
return []
else:
return [o.strip() for o in input_str.split(",") if o]
def convert_to_8bit(arr, clip_percentile = 2.5):
arr = np.clip(arr * (255.0 / np.percentile(arr, 100 - clip_percentile)), 0, 255)
return arr.astype(np.uint8)
def learn_regression_tree_ensemble(img_features, gt_illuminants, num_trees, max_tree_depth):
eps = 0.001
inst = [[img_features[i], gt_illuminants[i][0] / (sum(gt_illuminants[i]) + eps),
gt_illuminants[i][1] / (sum(gt_illuminants[i]) + eps)] for i in range(len(img_features))]
inst.sort(key = lambda obj: obj[1]) #sort by r chromaticity
stride = int(np.ceil(len(inst) / float(num_trees+1)))
sz = 2*stride
dst_model = []
for tree_idx in range(num_trees):
#local group in the training data is additionally weighted by num_trees
local_group_range = range(tree_idx*stride, min(tree_idx*stride+sz, len(inst)))
X = num_trees * [inst[i][0] for i in local_group_range]
y_r = num_trees * [inst[i][1] for i in local_group_range]
y_g = num_trees * [inst[i][2] for i in local_group_range]
#add the rest of the training data:
X = X + [inst[i][0] for i in range(len(inst)) if i not in local_group_range]
y_r = y_r + [inst[i][1] for i in range(len(inst)) if i not in local_group_range]
y_g = y_g + [inst[i][2] for i in range(len(inst)) if i not in local_group_range]
local_model = []
for feature_idx in range(len(X[0])):
tree_r = DecisionTreeRegressor(max_depth = max_tree_depth, random_state = 1234)
tree_r.fit([el[feature_idx][0] for el in X], y_r)
tree_g = DecisionTreeRegressor(max_depth = max_tree_depth, random_state = 1234)
tree_g.fit([el[feature_idx][0] for el in X], y_g)
local_model.append([tree_r, tree_g])
dst_model.append(local_model)
return dst_model
def get_tree_node_lists(tree, tree_depth):
dst_feature_idx = (2**tree_depth-1) * [0]
dst_thresh_vals = (2**tree_depth-1) * [.5]
dst_leaf_vals = (2**tree_depth) * [-1]
leaf_idx_offset = (2**tree_depth-1)
left = tree.tree_.children_left
right = tree.tree_.children_right
threshold = tree.tree_.threshold
value = tree.tree_.value
feature = tree.tree_.feature
def recurse(left, right, threshold, feature, node, dst_idx, cur_depth):
if (threshold[node] != -2):
dst_feature_idx[dst_idx] = feature[node]
dst_thresh_vals[dst_idx] = threshold[node]
if left[node] != -1:
recurse (left, right, threshold, feature, left[node], 2*dst_idx+1, cur_depth + 1)
if right[node] != -1:
recurse (left, right, threshold, feature, right[node], 2*dst_idx+2, cur_depth + 1)
else:
range_start = 2**(tree_depth - cur_depth) * dst_idx + (2**(tree_depth - cur_depth) - 1) - leaf_idx_offset
range_end = 2**(tree_depth - cur_depth) * dst_idx + (2**(tree_depth - cur_depth+1) - 2) - leaf_idx_offset + 1
dst_leaf_vals[range_start:range_end] = (range_end - range_start) * [value[node][0][0]]
recurse(left, right, threshold, feature, 0, 0, 0)
return (dst_feature_idx, dst_thresh_vals, dst_leaf_vals)
def generate_code(model, input_params, use_YML, out_file):
feature_idx = []
thresh_vals = []
leaf_vals = []
depth = int(input_params["--max_tree_depth"])
for local_model in model:
for feature in local_model:
(local_feature_idx, local_thresh_vals, local_leaf_vals) = get_tree_node_lists(feature[0], depth)
feature_idx += local_feature_idx
thresh_vals += local_thresh_vals
leaf_vals += local_leaf_vals
(local_feature_idx, local_thresh_vals, local_leaf_vals) = get_tree_node_lists(feature[1], depth)
feature_idx += local_feature_idx
thresh_vals += local_thresh_vals
leaf_vals += local_leaf_vals
if use_YML:
fs = cv.FileStorage(out_file, 1)
fs.write("num_trees", len(model))
fs.write("num_tree_nodes", 2**depth)
fs.write("feature_idx", np.array(feature_idx).astype(np.uint8))
fs.write("thresh_vals", np.array(thresh_vals).astype(np.float32))
fs.write("leaf_vals", np.array(leaf_vals).astype(np.float32))
fs.release()
else:
res = "/* This file was automatically generated by learn_color_balance.py script\n" +\
" * using the following parameters:\n"
for key in input_params:
res += " " + key + " " + input_params[key]
res += "\n */\n"
res += "const int num_features = 4;\n"
res += "const int _num_trees = " + str(len(model)) + ";\n"
res += "const int _num_tree_nodes = " + str(2**depth) + ";\n"
res += "unsigned char _feature_idx[_num_trees*num_features*2*(_num_tree_nodes-1)] = {" + str(feature_idx[0])
for i in range(1,len(feature_idx)):
res += "," + str(feature_idx[i])
res += "};\n"
res += "float _thresh_vals[_num_trees*num_features*2*(_num_tree_nodes-1)] = {" + ("%.3ff" % thresh_vals[0])[1:]
for i in range(1,len(thresh_vals)):
res += "," + ("%.3ff" % thresh_vals[i])[1:]
res += "};\n"
res += "float _leaf_vals[_num_trees*num_features*2*_num_tree_nodes] = {" + ("%.3ff" % leaf_vals[0])[1:]
for i in range(1,len(leaf_vals)):
res += "," + ("%.3ff" % leaf_vals[i])[1:]
res += "};\n"
f = open(out_file,"w")
f.write(res)
f.close()
def load_ground_truth(gt_path):
gt = scipy.io.loadmat(gt_path)
base_gt_illuminants = []
black_levels = []
if "groundtruth_illuminants" in gt.keys() and "darkness_level" in gt.keys():
#NUS 8-camera dataset format
base_gt_illuminants = gt["groundtruth_illuminants"]
black_levels = len(base_gt_illuminants) * [gt["darkness_level"][0][0]]
elif "real_rgb" in gt.keys():
#Gehler-Shi dataset format
base_gt_illuminants = gt["real_rgb"]
black_levels = 87 * [0] + (len(base_gt_illuminants) - 87) * [129]
else:
print("Error: unknown ground-truth format, only formats of Gehler-Shi and NUS 8-camera datasets are supported")
sys.exit(1)
return (base_gt_illuminants, black_levels)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description=("A tool for training the learning-based "
"color balance algorithm. Currently supports "
"training only on the Gehler-Shi and NUS 8-camera datasets."),
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"-i",
"--input_folder",
metavar="INPUT_FOLDER",
default="",
help=("Folder containing the training dataset. Assumes minimally "
"processed png images like in the Gehler-Shi (http://www.cs.sfu.ca/~colour/data/shi_gehler/) "
"or NUS 8-camera (http://www.comp.nus.edu.sg/~whitebal/illuminant/illuminant.html) datasets"))
parser.add_argument(
"-g",
"--ground_truth",
metavar="GROUND_TRUTH",
default="real_illum_568..mat",
help=("Path to the mat file containing ground truth illuminations. Currently "
"supports formats supplied by the Gehler-Shi and NUS 8-camera datasets."))
parser.add_argument(
"-r",
"--range",
metavar="RANGE",
default="0,0",
help="Range of images from the input dataset to use for training")
parser.add_argument(
"-o",
"--out",
metavar="OUT",
default="color_balance_model.yml",
help="Path to the output learnt model. Either a .yml (for loading during runtime) "
"or .hpp (for compiling with the main code) file ")
parser.add_argument(
"--hist_bin_num",
metavar="HIST_BIN_NUM",
default="64",
help=("Size of one dimension of a three-dimensional RGB histogram employed in the "
"feature extraction step."))
parser.add_argument(
"--num_trees",
metavar="NUM_TREES",
default="20",
help=("Parameter to control the size of the regression tree ensemble"))
parser.add_argument(
"--max_tree_depth",
metavar="MAX_TREE_DEPTH",
default="4",
help=("Maxmimum depth of regression trees constructed during training."))
parser.add_argument(
"-a",
"--num_augmented",
metavar="NUM_AUGMENTED",
default="2",
help=("Number of augmented samples per one training image. Training set "
"augmentation tends to improve the learnt model robustness."))
args, other_args = parser.parse_known_args()
if not os.path.exists(args.input_folder):
print("Error: " + args.input_folder + (" does not exist. Please, correctly "
"specify the -i parameter"))
sys.exit(1)
if not os.path.exists(args.ground_truth):
print("Error: " + args.ground_truth + (" does not exist. Please, correctly "
"specify the -g parameter"))
sys.exit(1)
img_range = list(map(int,parse_sequence(args.range)))
if len(img_range)!=2:
print("Error: Please specify the -r parameter in form <first_image_index>,<last_image_index>")
sys.exit(1)
use_YML = None
if args.out.endswith(".yml"):
use_YML = True
elif args.out.endswith(".hpp"):
use_YML = False
else:
print("Error: Only .hpp and .yml are supported as output formats")
sys.exit(1)
hist_bin_num = int(args.hist_bin_num)
num_trees = int(args.num_trees)
max_tree_depth = int(args.max_tree_depth)
img_files = sorted(os.listdir(args.input_folder))
(base_gt_illuminants,black_levels) = load_ground_truth(args.ground_truth)
features = []
gt_illuminants = []
i=0
sz = len(img_files)
random.seed(1234)
inst = cv.xphoto.createLearningBasedWB()
inst.setRangeMaxVal(255)
inst.setSaturationThreshold(0.98)
inst.setHistBinNum(hist_bin_num)
for file in img_files:
if (i>=img_range[0] and i<img_range[1]) or (img_range[0]==img_range[1]==0):
cur_path = os.path.join(args.input_folder,file)
im = cv.imread(cur_path, -1).astype(np.float32)
im -= black_levels[i]
im_8bit = convert_to_8bit(im)
cur_img_features = inst.extractSimpleFeatures(im_8bit, None)
features.append(cur_img_features.tolist())
gt_illuminants.append(base_gt_illuminants[i].tolist())
for iter in range(int(args.num_augmented)):
R_coef = random.uniform(0.2, 5.0)
G_coef = random.uniform(0.2, 5.0)
B_coef = random.uniform(0.2, 5.0)
im_8bit = im
im_8bit[:,:,0] *= B_coef
im_8bit[:,:,1] *= G_coef
im_8bit[:,:,2] *= R_coef
im_8bit = convert_to_8bit(im)
cur_img_features = inst.extractSimpleFeatures(im_8bit, None)
features.append(cur_img_features.tolist())
illum = base_gt_illuminants[i]
illum[0] *= R_coef
illum[1] *= G_coef
illum[2] *= B_coef
gt_illuminants.append(illum.tolist())
sys.stdout.write("Computing features: [%3d/%3d]\r" % (i, sz)),
sys.stdout.flush()
i+=1
print("\nLearning the model...")
model = learn_regression_tree_ensemble(features, gt_illuminants, num_trees, max_tree_depth)
print("Writing the model...")
generate_code(model,{"-r":args.range, "--hist_bin_num": args.hist_bin_num, "--num_trees": args.num_trees,
"--max_tree_depth": args.max_tree_depth, "--num_augmented": args.num_augmented},
use_YML, args.out)
print("Done")
+103
View File
@@ -0,0 +1,103 @@
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/xphoto.hpp>
#include "opencv2/xphoto/oilpainting.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void TrackSlider(int , void *);
static void addSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r);
vector<int> colorSpace = { COLOR_BGR2GRAY,COLOR_BGR2HSV,COLOR_BGR2YUV,COLOR_BGR2XYZ };
struct OilImage {
String winName = "Oil painting";
int size;
int dynRatio;
int colorSpace;
Mat img;
};
const String keys =
"{Help h usage ? help | | Print this message }"
"{v | 0 | video index }"
"{a | 700 | API index }"
"{s | 10 | neighbouring size }"
"{d | 1 | dynamic ratio }"
"{c | 0 | color space }"
"{@arg1 | | file path}"
;
int main(int argc, char* argv[])
{
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
String filename = parser.get<String>(0);
OilImage p;
p.dynRatio = parser.get<int>("d");
p.size = parser.get<int>("s");
p.colorSpace = parser.get<int>("c");
if (p.colorSpace < 0 || p.colorSpace >= static_cast<int>(colorSpace.size()))
{
std::cout << "Color space must be >= 0 and <"<< colorSpace.size()<<"\n";
return EXIT_FAILURE;
}
if (!filename.empty())
{
p.img = imread(filename);
if (p.img.empty())
{
std::cout << "Check file path!\n";
return EXIT_FAILURE;
}
Mat dst;
xphoto::oilPainting(p.img, dst, p.size, p.dynRatio, colorSpace[p.colorSpace]);
imshow("oil painting effect", dst);
waitKey();
return 0;
}
VideoCapture v(parser.get<int>("v")+ parser.get<int>("a"));
v>> p.img;
p.winName="Oil Painting";
namedWindow(p.winName);
addSlider("DynRatio", p.winName, 1,127,p.dynRatio,&p.dynRatio, TrackSlider, &p);
addSlider("Size", p.winName, 1, 100, p.size, &p.size, TrackSlider, &p);
addSlider("ColorSpace", p.winName, 0, static_cast<int>(colorSpace.size()-1), p.colorSpace, &p.colorSpace, TrackSlider, &p);
while (waitKey(20) != 27)
{
v>>p.img;
imshow("Original", p.img);
TrackSlider(0, &p);
waitKey(10);
}
return 0;
}
void addSlider(String sliderName, String windowName, int minSlider, int maxSlider, int valDefault, int *valSlider, void(*f)(int, void *), void *r)
{
createTrackbar(sliderName, windowName, valSlider, 1, f, r);
setTrackbarMin(sliderName, windowName, minSlider);
setTrackbarMax(sliderName, windowName, maxSlider);
setTrackbarPos(sliderName, windowName, valDefault);
}
void TrackSlider(int , void *r)
{
OilImage *p = (OilImage *)r;
Mat dst;
p->img = p->img / p->dynRatio;
p->img = p->img*p->dynRatio;
xphoto::oilPainting(p->img, dst, p->size, p->dynRatio,colorSpace[p->colorSpace]);
if (!dst.empty())
{
imshow(p->winName, dst);
}
}