Этот ответ предполагает, что у вас есть функция генератора случайных битов, поскольку std::random_shuffle
требует этого. Я не знаю, как работает xor128
, поэтому я воспользуюсь функциями библиотеки <random>
.
Если у нас есть совокупность N
элементов, и мы хотим выбрать группы по размеру j
и k
случайным образом из этой совокупности без пересечения, мы можем записать индекс каждого элемента на карте, перетасовать колоду, взять j
карт, а затем вытянуть k
карт. Все, что осталось, выбрасывается. Этого можно добиться с помощью библиотеки <random>
. Ожидается ответ о том, как включить собственный ГПСЧ, как вы реализовали с помощью xor128
.
Это предполагает, что random_device
не будет работать в вашей системе (многие компиляторы реализуют его таким образом, что он всегда будет возвращать та же последовательность), поэтому мы заполняем случайный генератор текущим временем, как старый добрый srand
, который делала наша мать.
Непроверено, так как я не знаю, как использовать OpenCV. Любой, кто хоть немного разбирается в этом, отредактируйте его соответствующим образом.
#include <ctime> // for std::time
#include <numeric> // for std::iota
#include <random>
#include <vector>
void effect1(Mat& img, float amount, std::mt19937 g) // 0.0 ≥ amount ≥ 1.00
{
std::vector<cv::Size> ind(img.total());
std::iota(ind.begin(), ind.end(), 0); // fills with 0, 1, 2, ...
std::random_shuffle(ind.begin(), ind.end(), g);
cv::Size count = img.total() * amount;
auto white = get_white<Mat>(); // template function to return this matrix' concept of white
// could easily replace with cv::Vec3d(255,255,255)
// if all your matrices are 3 channel?
auto black = get_black<Mat>(); // same but... opposite
auto end = ind.begin() + count;
for (auto it = ind.begin(), it != end; ++it)
{
img.at(*it) = white;
}
end = (ind.begin() + 2 * count) > ind.end() ?
ind.end() :
ind.begin() + 2 * count;
for (auto it = ind.begin() + count; it != end; ++it)
{
img.at(*it) = black;
}
}
int main()
{
std::mt19937 g(std::time(nullptr)); // you normally see this seeded with random_device
// but that's broken on some implementations
// adjust as necessary for your needs
cv::Mat mat = ... // make your cv objects
effect1(mat, 0.1, g);
// display it here
}
Другой подход
Вместо перетасовки индексов и извлечения карт из колоды предположите, что каждый пиксель имеет случайную вероятность переключения на белый, переход на черный или оставшийся прежним. Если ваша сумма равна 0,4, выберите случайное число от 0,0 до 1,0, при любом результате от 0,0 до 0,4 пиксель станет черным, а между 0,4 и 0,8 - белым, в противном случае он останется прежним.
Общий алгоритм :
given probability of flipping -> f
for each pixel in image -> p:
get next random float([0.0, 1.0)) -> r
if r < f
then p <- BLACK
else if r < 2*f
then p <- WHITE
Вы не получите каждый раз одинаковое количество белых / черных пикселей, но это случайность! Мы все равно генерируем случайное число для каждого пикселя для алгоритма перетасовки. У него такая же сложность, если я не ошибаюсь.