При прохождении теста 1 в нем оказались вопросы, который во-первых в 1 лекции не рассматривались, во-вторых, оказалось, что вопрос был рассмаотрен в самостоятельно работе №2. Это значит, что их нужно выполнить перед прохождением теста? или это ошибка? |
Базовые операции обработки изображений
2.7. Вычисление гистограмм
Один из наиболее распространенных дефектов фотографических, сканерных и телевизионных изображений – слабый контраст. Дефект во многом обусловлен ограниченностью диапазона воспроизводимых яркостей. Под контрастом понимается разность максимального и минимального значений яркости. Контрастность изображения можно повысить за счет изменения яркости каждого элемента изображения и увеличения диапазона яркостей. Существует несколько методов, основанных на вычислении гистограммы.
Допустим, что имеется изображение в оттенках серого, интенсивность пикселей которого изменяется в пределах значений от до , где и . Для изображения можно построить гистограмму со столбцами, отвечающими количеству пикселей определенной интенсивности. Такого рода гистограмма позволяет представить распределение оттенков на изображении. В общем случае под гистограммой понимается коллекция целочисленных значений, каждое из которых определяет количество точек, обладающих некоторым свойством или принадлежащих определенному бину. На практике гистограммы применяются, чтобы получить статистическую картину о распределении каких-либо данных (пикселей, векторов признаков, направлений градиента во всех точках изображения и т.п.).
В данном разделе остановимся на рассмотрении структур данных и функций OpenCV, обеспечивающих вычисление гистограмм. Ниже приведены прототипы доступных функций.
void calcHist(const Mat* arrays, int narrays, const int* channels, const Mat& mask, MatND& hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false) void calcHist(const Mat* arrays, int narrays, const int* channels, const Mat& mask, SparseMat& hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false)
Параметры:
- arrays – исходные массивы данных или изображения. Должны иметь одинаковую глубину (CV_8U или CV_32F) и размер.
- narrays – количество исходных массивов данных.
- channels – массив индексов каналов в каждом входном массиве, по которым будет вычисляться гистограмма.
- mask – маска, на которой считается гистограмма. Опциональный параметр. Если маска не пуста, то она представляется 8-битной матрицей того же размера, что и каждый исходный массив. При построении гистограммы учитываются только элементы массивов, которые соответствуют ненулевым элементам маски. Если маска пуста, то построение гистограммы выполняется на полном наборе данных.
- hist – результирующая гистограмма, плотная в случае использования первого прототипа функции, разреженная – в случае второго. Для хранения плотной гистограммы используется структура данных MatND, для разреженной – SparseMat. MatND представляется в виде n-мерного массива, SparseMat – хэш-таблицей ненулевых значений [10].
- dims – размерность гистограммы. Параметр принимает положительные целочисленные значения, не превышающие CV_MAX_DIMS = 32.
- histSize – количество бинов по каждой размерности гистограммы.
- ranges – интервалы изменения значений по каждой размерности гистограммы. Если гистограмма равномерная (uniform = true), то для любой размерности i достаточно указать только нижнюю границу изменения (по существу значение, соответствующее первому бину), верхняя граница будет совпадать с histSize[i]-1.
- uniform – флаг, который определяет тип диаграммы (равномерная или нет).
- accumulate – флаг, указывающий на необходимость очищения гистограммы перед непосредственными вычислениями. Использование данного флага позволяет использовать одну и ту же гистограмму для нескольких множеств массивов или обновлять гистограмму во времени.
Рассмотрим пример программы, которая осуществляет построение и отображение гистограмм по каждому каналу цветного изображения. Программа получает в качестве аргументов командной строки название изображения, расщепляет полученную матрицу по каналам (split) и вычисляет гистограмму для каждого канала изображения (calcHist). Заметим, что в OpenCV каналы изображения хранятся в порядке BGR, а не в RGB. Далее выполняется нормализация гистограмм (normalize) для приемлемого отображения в виде ломаных.
#include <stdio.h> #include <opencv2/opencv.hpp> using namespace cv; const char helper[] = "Sample_calcHist.exe <img_file>\n\ \t<img_file> - image file name\n"; int main(int argc, char* argv[]) { const char *initialWinName = "Initial Image", *histWinName = "Histogram"; Mat img, bgrChannels[3], bHist, gHist, rHist, histImg; int kBins = 256; // количество бинов гистограммы // интервал изменения значений бинов float range[] = {0.0f, 256.0f}; const float* histRange = { range }; // равномерное распределение интервала по бинам bool uniform = true; // запрет очищения перед вычислением гистограммы bool accumulate = false; // размеры для отображения гистограммы int histWidth = 512, histHeight = 400; // количество пикселей на бин int binWidth = cvRound((double)histWidth / kBins); int i, kChannels = 3; Scalar colors[] = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)}; if (argc < 2) { printf("%s", helper); return 1; } // загрузка изображения img = imread(argv[1], 1); // выделение каналов изображения split(img, bgrChannels); // вычисление гистограммы для каждого канала calcHist("bgrChannels[0], 1, 0, Mat(), bHist, 1, "kBins, "histRange, uniform, accumulate); calcHist("bgrChannels[1], 1, 0, Mat(), gHist, 1, "kBins, "histRange, uniform, accumulate); calcHist("bgrChannels[2], 1, 0, Mat(), rHist, 1, "kBins, "histRange, uniform, accumulate); // построение гистограммы histImg = Mat(histHeight, histWidth, CV_8UC3, Scalar(0, 0, 0)); // нормализация гистограмм в соответствии с размерам // окна для отображения normalize(bHist, bHist, 0, histImg.rows, NORM_MINMAX, -1, Mat()); normalize(gHist, gHist, 0, histImg.rows, NORM_MINMAX, -1, Mat()); normalize(rHist, rHist, 0, histImg.rows, NORM_MINMAX, -1, Mat()); // отрисовка ломаных for (i = 1; i < kBins; i++) { line(histImg, Point(binWidth * (i-1), histHeight-cvRound(bHist.at<float>(i-1))) , Point(binWidth * i, histHeight-cvRound(bHist.at<float>(i)) ), colors[0], 2, 8, 0); line(histImg, Point(binWidth * (i-1), histHeight-cvRound(gHist.at<float>(i-1))) , Point(binWidth * i, histHeight-cvRound(gHist.at<float>(i)) ), colors[1], 2, 8, 0); line(histImg, Point(binWidth * (i-1), histHeight-cvRound(rHist.at<float>(i-1))) , Point(binWidth * i, histHeight-cvRound(rHist.at<float>(i)) ), colors[2], 2, 8, 0); } // отображение исходного изображения и гистограмм namedWindow(initialWinName, CV_WINDOW_AUTOSIZE); namedWindow(histWinName, CV_WINDOW_AUTOSIZE); imshow(initialWinName, img); imshow(histWinName, histImg); waitKey(); // закрытие окон destroyAllWindows(); // осовобождение памяти img.release(); for (i = 0; i < kChannels; i++) { bgrChannels[i].release(); } bHist.release(); gHist.release(); rHist.release(); histImg.release(); return 0; }
Результат запуска программы на тестовом изображении из набора PASCAL VOC 2007 показан на рисунке (рис. 7.10) ниже.