16. OpenCV шаг за шагом. Генерация случайных чисел

1. OpenCV шаг за шагом. Введение.
2. Установка.
3. Hello World.
4. Загрузка картинки.
5. Вывод видео
6. Ползунок
7. Захват видео с камеры
8. Запись видео
9. События от мышки
10. Обработка изображения — сглаживание
11. Обработка изображения — изменение размеров
12. ROI — интересующая область изображения
13. Типы данных OpenCV
14. Матрица
15. Сохранение данных в XML
16. Генерация случайных чисел

Рассмотрим функции, которые предоставляет OpenCV для генерации псевдо-случайных чисел.

CV_INLINE  void  cvRandInit( CvRandState* state, double param1,
                             double param2, int seed,
                             int disttype CV_DEFAULT(CV_RAND_UNI))
-инициализация работы с ГСЧ

state — указатель на структуру ГСЧ:
typedef struct CvRandState
{
    CvRNG     state;    /* RNG state (the current seed and carry)*/
    int       disttype; /* distribution type */
    CvScalar  param[2]; /* parameters of RNG */
}
CvRandState;

param1 — первый параметр распределения (в случае однородного — это нижняя граница диапазона, в случае нормального — величина случайных чисел)
param2 — второй параметр распределения (в случае однородного — это верхняя граница диапазона, в случае нормального — стандартное отклонение случайных чисел).
seed — начальная установка
disttype — тип распределения:
#define CV_RAND_UNI 0
#define CV_RAND_NORMAL 1

CV_INLINE  void  cvRandSetRange( CvRandState* state, double param1,
                                 double param2, int index CV_DEFAULT(-1))
— изменение диапазона ГСЧ с сохранением состояния ГСЧ

state — указатель на структуру ГСЧ
param1
param2
index

CV_INLINE void cvRand( CvRandState* state, CvArr* arr )
— заполнение массива случайными значениями
state — указатель на структуру ГСЧ
arr — указатель на массив для заполнения

фактически сводится к вызову:
cvRandArr( &state->state, arr, state->disttype, state->param[0], state->param[1] );


CVAPI(void) cvRandArr( CvRNG* rng, CvArr* arr, int dist_type,
                      CvScalar param1, CvScalar param2 );

— заполнение массива случайными значениями

rng — указатель на состояние ГСЧ
typedef uint64 CvRNG;

arr — указатель на массив для заполнения
dist_type — тип распределения
param1 — первый параметр распределения (в случае однородного — это нижняя граница диапазона, в случае нормального — величина случайных чисел)
param2 — второй параметр распределения (в случае однородного — это верхняя граница диапазона, в случае нормального — стандартное отклонение случайных чисел).

typedef uint64 CvRNG;

// инициализация состояния ГСЧ
CV_INLINE CvRNG cvRNG( int64 seed CV_DEFAULT(-1))
{
    CvRNG rng = seed ? (uint64)seed : (uint64)(int64)-1;
    return rng;
}

// возвращает случайное 32-bit unsigned int
CV_INLINE unsigned cvRandInt( CvRNG* rng )
{
    uint64 temp = *rng;
    temp = (uint64)(unsigned)temp*4164903690U + (temp >> 32);
    *rng = temp;
    return (unsigned)temp;
}

// возвращает случайное float между 0 and 1
CV_INLINE double cvRandReal( CvRNG* rng )
{
    return cvRandInt(rng)*2.3283064365386962890625e-10 /* 2^-32 */;
}


В качестве примера рассмотрим засеивание изображение 3% шума.

//
// засеиваем изображение шумом
//

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* dst = 0;

int main(int argc, char* argv[])
{
	// имя картинки задаётся первым параметром
	char* filename = argc >= 2 ? argv[1] : "Image0.jpg";
	// получаем картинку
	image = cvLoadImage(filename,1);
	assert( image != 0 );

	// клонируем картинку 
	dst = cvCloneImage(image);

	int count = 0;

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("noise",CV_WINDOW_AUTOSIZE);

	// инициализация состояния ГПСЧ
	CvRNG rng = cvRNG(0xffffffff);

	// пробегаемся по всем пикселям изображения
	for( int y=0; y<dst->height; y++ ) {
		uchar* ptr = (uchar*) (dst->imageData + y * dst->widthStep);
		for( int x=0; x<dst->width; x++ ) {
			if(cvRandInt(&rng)%100>=97){
				// 3 канала 
				ptr[3*x] = cvRandInt(&rng)%255; // B
				ptr[3*x+1] = cvRandInt(&rng)%255; // G
				ptr[3*x+2] = cvRandInt(&rng)%255; // R
				count++;
				/**
				// красные пиксели
				ptr[3*x]=0;
				ptr[3*x+1]=0;
				ptr[3*x+2]=255;
				/**/
			}
		}
	}
	printf("[i] noise: %d (%.2f%c)\n", count, (float)count/(dst->height*dst->width)*100, '%');

	// показываем картинку
	cvShowImage("original",image);
	cvShowImage("noise",dst);

	// ждём нажатия клавиши
	cvWaitKey(0);

	// освобождаем ресурсы
	cvReleaseImage(&image);
	cvReleaseImage(&dst);
	// удаляем окна
	cvDestroyWindow("original");
	cvDestroyWindow("noise");
	return 0;
}



по типу макроса CV_MAT_ELEM можно написать макрос для получения заданного пикселя изображения:
#define CV_PIXEL(type,img,x,y) (((type*)(img->imageData+(y)*img->widthStep))+(x)*img->nChannels)


тогда вот как будет выглядеть обход всех пикселей 3-канального изображения из примера засеивания шумом:

	// пробегаемся по всем пикселям изображения
	for( int y=0; y<dst->height; y++ ) {
		for( int x=0; x<dst->width; x++ ) {
			if(cvRandInt(&rng)%100>=97){
				// 3 канала 
				CV_PIXEL(unsigned char, dst, x, y)[0] = cvRandInt(&rng)%255; // B
				CV_PIXEL(unsigned char, dst, x, y)[1] = cvRandInt(&rng)%255; // G
				CV_PIXEL(unsigned char, dst, x, y)[2] = cvRandInt(&rng)%255; // R
				count++;
			}
		}
	}


Далее: 17. OpenCV шаг за шагом. Обработка изображения — морфологические преобразования
  • 0
  • 9 сентября 2010, 10:55
  • noonv

Комментарии (10)

RSS свернуть / развернуть
+
0
а как получить, скажем 10 чисел при param1 = 10, param2 = 3, dist_type = 1 (НЗР) ?!
чет нифига не получается…
avatar

ns5d

  • 22 августа 2012, 20:03
+
0
наверно так…
#include <stdio.h>
#include <stdlib.h>
#include "cv.h"
#include "cvaux.h"
#include "cxcore.h"
#include "highgui.h"


int main( int argc, char** argv )
{
	int n = 10;
	int m = 1;
	CvMat* noise = cvCreateMat(n, m, CV_8UC1 );
	//CvRNG rng[] = { cvRNG(time(NULL)), cvRNG(time(NULL)) };
	CvRNG rng[] = {cvRNG(10)};
	//>//CvRNG rng[] = {cvRNG(10), cvRNG(10)};
	//CvRNG rng = cvRNG(0xffffffff);
    // seems only cvScalar(first) is effective
	//>//cvRandArr(rng, noise, CV_RAND_UNI, cvScalar(0,0), cvScalar(15,2) );
	cvRandArr(rng, noise, CV_RAND_NORMAL, cvScalar(10), cvScalar(3) );
	//cvRandArr(rng, noise, CV_RAND_UNI, cvScalar(5), cvScalar(10) );
	//cvPrintMat( noise );
	for (int i=0; i<n; i++) {
		for (int j=0; j<m; j++) {
			printf("  %.0f", cvGetReal2D(noise, i, j));
		}
		printf("\n");
	}

    return 0;
}
avatar

ns5d

  • 23 августа 2012, 10:36
+
0
примера рассмотрим засеивание изображение 3% шума

а где видно что это три процента шума?
avatar

Zybr

  • 20 февраля 2014, 19:58
+
0
Интересно, а зачем нужны все эти функции, если в стандартной библиотеке уже есть функции для работы со случайными числами.
avatar

laborer

  • 23 марта 2015, 01:30
+
0
Для независимости от стандартных библиотек?
avatar

Evtomax

  • 10 августа 2015, 01:42
+
0
В данном случае стандартная библиотека — это фактически часть языка (C или C++), без неё никак.
avatar

laborer

  • 10 августа 2015, 09:26
+
0
OpenCV доступна на разных языках. Я, например, пишу на c#, кто-то на python-е, а кто-то может свой собственный язык разработает :) И у него не будет стандартного способа генерации псевдослучайных чисел, или будут свои нехорошие особенности…
avatar

JohnJ

  • 10 августа 2015, 09:59
+
0
А как задать линейчатый шум?
avatar

Mikney

  • 18 апреля 2017, 01:25
+
0
Не встречал — видимо, придётся реализовывать самостоятельно.
avatar

noonv

  • 24 апреля 2017, 14:02

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.