Список литературы:
1. Я.А. Фурман, А.В. Кревецкий «Введение в контурный анализ. Приложение к обработке изображений и сигналов» 2-у изд., испр. М. 2003г
2. «Сегментация изображения» http://habrahabr.ru/post/128768/ (дата обращения 10.04.2015)
3. «Обнаружение объектов методом Оцу» http://habrahabr.ru/post/112079/ (дата обращения 10.04.2015)
4. Н.М. Новикова «Структурное распознавание образов» Воронеж 2008г.
5. Phiplastic «Модуль бинаризации цветных изображений» http://www.phiplastic.com/prsntns/color_ru.pdf (дата обращения 10.04.2015)
6. Д.П. Николаев, А. А. Сараев «Критерии оценки качества в задаче автоматизированной настройки алгоритмов бинаризации»
7. Ю.А. Огруздина «Алгоритмы сегментации изображений» // Молодежный научно-технический вестник
8. В. Т. Фисенко, Т. Ю. Фисенко «Компьютерная обработка и распознавание изображений» учебное пособие ИТМО СПб 2008
Приложение
Функция ConSquareColorDif (нахождение оптимальной яркости для каждой точки изображения как максимум контуров попадающих в окрестность пиксела)
public static int [][][] ConSquareColorDif (int pixels[], int frameWidth, int frameHeight, int stepsHor, int stepsVer, int brightStep)
//Общее название класса трехмерный массив который возвращает оптимальную яркость для каждого пикселя.
1.1 Объявление переменных
public static int [][][] ConSquareColorDif (int pixels[], int frameWidth, int frameHeight, int stepsHor, int stepsVer, int brightStep)
//Общее название класса трехмерный массив который возвращает оптимальную яркость для каждого пикселя.
{
int iWidth = frameWidth;
int iHeight = frameHeight;
int [][][] result = new int [iHeight][iWidth][2];
int widthStep = iWidth / stepsHor; //Ширина окрестности
int heightStep = iHeight / stepsVer; //Высота окрестности
int [][][]squareBrightMax = new int [iHeight][iWidth][2]; //Оптимальная яркость для каждого пикселя
for (int[][] squareBrightMax1 : squareBrightMax) {
for (int[] squareBrightMax11 : squareBrightMax1) {
Arrays.fill(squareBrightMax11, 0);
}
}
//для каждого порога яркости вычисляем контуры.
for (int brightLevel = 0; brightLevel < 256; brightLevel += brightStep)
{
//получение черно-белой картинки
int[] bwPixs = ImageMethods.blackWhiteScale(pixels, brightLevel, ImageMethods.L_HUMAN_NTSC);
//начало прохода "квадратом"
//определяю отдельно прогонку по пикселям.
int pVer = 0;
int pHor = 0;
for (pVer = 0; pVer < iHeight; pVer++)
{
for (pHor = 0; pHor < iWidth; pHor++)
{
//Суть метода в том что мы берем область вокруг пикселя
//а следовательно мы должны избавиться от случаев, когда мы случайно выходим за границы
1.2 Обработка граничных случаев
int pHorBeg = pHor - widthStep/2;
if (pHorBeg < 0)
{
pHorBeg = 0;
}
int pHorEnd = pHor + widthStep/2;
if (pHorEnd >= iWidth)
{
pHorEnd = iWidth - 1;
}
int pVerBeg = pVer - heightStep/2;
if (pVerBeg < 0)
{
pVerBeg = 0;
}
int pVerEnd = pVer + heightStep/2;
if (pVerEnd >= iHeight)
{
pVerEnd = iHeight - 1;
}
int temp = 0;
//Прогонка в 4 шага, по часовой стрелке
1.3 Поиск оптимального значения яркости
//Верхняя грань слева направо
for (int i = pHorBeg + 1; i <= pHorEnd; i++)
{
int j = pVerBeg;
}
//Правая грань сверху вниз
for (int j = pVerBeg + 1; j <= pVerEnd; j++)
{
int i = pHorEnd;
if (bwPixs[i + j * iWidth] - bwPixs[i + (j - 1) * iWidth] != 0)
{
temp ++;
}
}
//Нижняя грань справа налево
for (int i = pHorEnd - 1; i >= pHorBeg; i--)
{
int j = pVerEnd;
if (bwPixs[i + j * iWidth] - bwPixs[(i + 1) + j * iWidth] != 0)
{
temp ++;
}
}
//Левая грань снизу вверх
for (int j = pVerEnd - 1; j >= pVerBeg; j--)
{
int i = pHorBeg;
if (bwPixs[i + j * iWidth] - bwPixs[i + (j + 1) * iWidth] != 0)
{
temp ++;
}
}
//Сравнение с макс значением
if (squareBrightMax[pVer][pHor][1] < temp)
{
squareBrightMax[pVer][pHor][0] = brightLevel;
squareBrightMax[pVer][pHor][1] = temp;
}
}
}
}
return squareBrightMax;
}
Функция avSquare (сглаживание исходной картинки)
/**
* Возвращает среднюю из оптимальных яркостей пикселей окрестности данного пикселя.
* @param pixContourCount Массив оптимальных значений яркостей для каждого пикселя из окрестнсти.
* @param stepVer Высота прямоугольного окна (окрестности).
* @param stepHor Ширина прямоугольного окна (окрестности).
* @return Трёхмерный массив
* 0, 1 - координаты пикселя в картинке
* 2 - одномерный массив [0] - яркость средняя из оптимальных яркостей [1] - среднее количество контуров по пикселям окрестности
*/
public static int[][][] avSquare(int[][][] pixContourCount, int stepsHor, int stepsVer) {
int height = pixContourCount.length;
int width = pixContourCount[0].length;
int stepHor = width / stepsHor / 2;
int stepVer = height / stepsVer / 2;
int[][][] result = new int[height][width][2];
int tempPtVer = 0;
int tempPtHor = 0;
for (int pVer = 0; pVer < height; pVer++) {
// System.out.println("pVer " + pVer);
for (int pHor = 0; pHor < width; pHor++) {
int tempBright = 0;
int tempQ = 0;
for (int ptVer = pVer - stepVer; ptVer < pVer + stepVer; ptVer++) {
tempPtVer = ptVer;
if (tempPtVer < 0) {
tempPtVer = 0;
}
if (tempPtVer >= height) {
tempPtVer = height - 1;
}
for (int ptHor = pHor - stepHor; ptHor < pHor + stepHor; ptHor++) {
tempPtHor = ptHor;
if (tempPtHor < 0) {
tempPtHor = 0;
}
if (tempPtHor >= width) {
tempPtHor = width - 1;
}
tempBright += pixContourCount[tempPtVer][tempPtHor][0];
tempQ += pixContourCount[tempPtVer][tempPtHor][1];
}
}
result[pVer][pHor][0] = tempBright / (stepHor * stepVer * 4);
result[pVer][pHor][1] = tempQ / (stepHor * stepVer * 4);
}
}
System.out.println("" + result[100][100][0]);
return result;
}
Функция squarBinar (Бинаризует изображение в соответствии с порогом яркости)
public static int[] squarBinar(int pixels[], int[][][] avSquare) {
int height = avSquare.length;
int width = avSquare[0].length;
int[] result = new int[pixels.length];
for (int j = 0, k = 0; j < height; j++) {
for (int i = 0; i < width; i++, k++) {
// result[i][j] = ImageMethods.blackWhiteScale(pixels, avSquare[i][j][0], ImageMethods.L_HUMAN_NTSC);
if (ImageMethods.pixelBrightnessNTSC(pixels[k]) < avSquare[j][i][0]) {
result[k] = 0xFF000000;
} else {
result[k] = 0xFFFFFFFF;
}
}
}
return result;
}
Функция maxNumberContourBrights (нахождение максимального количества контуров при прогонке по яркости для каждого сегмента)
* Картинка разбивается на прямоугольники, для каждого из которых вычисляется
* порог яркости чёрно-белого разбиения, дающий наибольшее число контуров.
* @param pixels Пиксели картинки.
* @param frameWidth Ширина картинки.
* @param frameHeight Высота картинки.
* @param stepsHor Число разбиений по горизонтали.
* @param stepsVer Число разбиений по вертикали.
* @return Массив значений (яркость[0], число[1]) для каждого прямоугольника.
*/
public static int[][][] maxNumberCountourBrights(int pixels[], int frameWidth, int frameHeight, int stepsHor, int stepsVer, int brightStep) {
int[][][] result = new int[stepsVer][stepsHor][2];
int widthStep = frameWidth / stepsHor; //Шаг для ячейки по ширине
int heightStep = frameHeight / stepsVer; //Шаг для ячейки по высоте
int[][] conBrightMax = new int[stepsVer][stepsHor]; //Ф-я порога для каждого сегмента, должна копировать conBrightMax[i][g] из предыдушей функци
int wigthstart = 0; //Эти две переменные нужны чтобы определить квадрат, на котором будет проводиться алгоритм
int heightStart = 0; //выделения контуров
int[] bwPixs;// = new int[pixels.length];
//Для каждого порога яркости вычисляем контуры.
for (int brightLevel = 0; brightLevel < 256; brightLevel += brightStep) {
//Получение чёрно-белой картинки.
bwPixs = ImageMethods.blackWhiteScale(pixels, brightLevel, ImageMethods.L_HUMAN_NTSC); //Black-WHITE
//Получение контуров.
ArrayList<Contour> contours = DetectContourMethods.constructFilledContoursWithProperties(bwPixs, frameWidth, 0xFF000000, 0xFFFFFFFF);
int[][] contourCounts = new int[stepsVer][stepsHor];
//Обнуление счётчика контуров в каждой области.
for (int[] contourCount : contourCounts) {
Arrays.fill(contourCount, 0);
}
for (Contour contour : contours) {
for (int i = 0; i < contourCounts.length; i++) {
for (int j = 0; j < contourCounts[i].length; j++) {
Rectangle rect = new Rectangle(j * widthStep , i * heightStep, widthStep, heightStep);
Point[] points = contour.getContourProperties().points;
int[] px = new int[points.length];
int[] py = new int[points.length];
for (int k = 0; k < points.length; k++) {
px[k] = points[k].x;
py[k] = points[k].y;
}
Polygon pol = new Polygon(px, py, points.length);
if (pol.intersects(j * widthStep , i * heightStep, widthStep, heightStep)) {
contourCounts[i][j]++;
}
}
}
}
for (int i = 0; i < contourCounts.length; i++) {
for (int j = 0; j < contourCounts[i].length; j++) {
if (contourCounts[i][j] > result[i][j][1]){
result[i][j][1] = contourCounts[i][j];
result[i][j][0] = brightLevel;
}
}
}
}
return result;
}
Функция contour contourAnalisys (Сегментация и выявление средних углов направления главной оси инерции)
public static double [][][] contourAnalisys(int squarBinar[], int width, int stepHor, int stepVer){
int height = squarBinar.length / width;
double[][][] result = new double[height][width][1];
ArrayList<Contour> contours = DetectContourMethods.constructFilledContoursWithProperties(squarBinar, width, 0xFF000000, 0xFFFFFFFF);
int widthStep = width / stepHor; //Ширина окрестности
int heightStep = height / stepVer; //Высота окрестности
int pVer = 0;
int pHor = 0;
for(; pVer<width; pVer++){
for(; pHor < height; pHor++){
int pHorBeg = pHor - widthStep / 2;
if (pHorBeg < 0) {
pHorBeg = 0;
}
int pHorEnd = pHor + widthStep / 2;
if (pHorEnd >= width) {
pHorEnd = width - 1;
}
int pVerBeg = pVer - heightStep / 2;
if (pVerBeg < 0) {
pVerBeg = 0;
}
int pVerEnd = pVer + heightStep / 2;
if (pVerEnd >= height) {
pVerEnd = height - 1;
}
int temp = 0;
TreeSet<Integer> cNums = new TreeSet();
for (int iVer = pVerBeg; iVer < pVerEnd; iVer++) {
for (int iHor = pHorBeg; iHor < pHorEnd; iHor++) {
int k = iVer * width + iHor;
int countNum = squarBinar[k] & 0x00FFFFFF;
if (countNum > 0) {
temp++;
cNums.add(countNum);
}
}
}
double sum = 0;
for (int cNum : cNums) {
sum += contours.get(cNum).getContourProperties().angleInertia;
}
result[pVer][pHor][0] = sum / cNums.size();
}
}
return result;
}
