@My1Name

Как реализовать алгоритм сегментации?

Для выделения области на изображении в цветовом диапазоне, я использую матрицу 3x3. В позиции x,y производится выборка последующих координат (a,b,c,d), куда будет сдвинут крестик, с предварительной проверкой диапазона. То есть в первой точке (x,y) берутся цветовые параметры для a,b,c,d. А именно: Вычисляется альфа-канал и, пожалуй на этом всё.. Если например С выходит за пределы диапазона взятого в первоначальной точке (x,y), то для С делаются ещё шаги в право и проверяется, не один ли это писксель выбился с диапазона?6390d603c2a6e189827212.jpeg
Программно это выглядит следующим образом: Берём параметры в позиции X,Y
private static String [] getColor(int x, int y) {
		Color color = new Color(image.getRGB(x, y));
		int red = color.getRed();
		int green = color.getGreen();
		int blue = color.getBlue();
//записывается последовательность цветов и сортируется (бессмысленная процедура)
		String R = "red#"+red, G="green#"+green, B="blue#"+blue;
		String [] colors = {R,G,B,"alpha"};
		Tools tools = new Tools();
		colors = tools.sortRGB(colors);
//считаем среднее значение светимости для 3-х цветов
		int alpha = (red+green+blue)/3;
		colors[3]=Integer.toString(alpha);
	return colors;
	}

Проверяем соответствие параметров для a,b,c,d, взятых в первоначальной точке X,Y
private static boolean colorRange(int x, int y, String [] RGB, String direction) {
		boolean range=false;
		int [] red = new int [9];
		int [] green = new int [9];
		int [] blue = new int [9];
		int pick=0;
//строим квадратик (матрицу) 3х3 (можно больше)
		int x1=x-1, x2=x+1, y1=y-1, y2=y+1;
		for (int X=x1; X<=x2; X++) {
			for (int Y=y1; Y<=y2; Y++) {
				try { 
					Color color = new Color(image.getRGB(X,Y));
					red[pick] = color.getRed();
					green[pick] = color.getGreen();
					blue [pick] = color.getBlue();
				}catch (ArrayIndexOutOfBoundsException e) {
					red[pick] = 0;
					green[pick] = 0;
					blue [pick] = 0;
				}
			pick++;
			}
		}
//считаем среднее значение для матрицы и сравниваем с параметрами точки X,Y
		int R = average(red);
		int G = average(green);
		int B = average(blue);
		int alpha = (R+B+G)/3;
		int alpha1 = Integer.parseInt(RGB[3]);
		if(alpha1-alpha<3 && alpha1-alpha>-3) {
				 return true;
		}else {
// Если вышли за диапазон, проверяем ещё пару пикселей в соответствии с направлением 
			switch (direction) {
	 		case "top" : if (y-5>0) { range=chekBorder(x,y, direction, RGB); } break;  
	 		case "left" :  if (x-5>0) { range=chekBorder(x,y, direction, RGB); } break;  
	 		case "right" : if (x+5<image.getWidth()) { range=chekBorder(x,y, direction, RGB); } break;
	 		case "bottom" : if (y+5<image.getHeight()) { range=chekBorder(x,y, direction, RGB); } break;
			}
		}
	return range;
	}

Предполагается, если пиксель вышел за диапазон, то должно быть это граница объекта:
private static boolean chekBorder(int x, int y, String direction, String [] RGB) {
		int alpha1 = Integer.parseInt(RGB[3]);
		int alpha, R,G,B;
		int var=0;
		boolean vectorX=false;
		switch (direction) {
		 case "top" : var=-1; break;  
		 case "left" : var=-1; vectorX=true; break;  
		 case "right" : var=1; vectorX=true; break;
		 case "bottom" : var=1; break;
		}
		int count=0;
		int [] point = new int [5];
//делаем 5 шагов в соответствии с направлением 
		for(int i=0;i<5;i++) {
			if(vectorX) {
				x=x+(var);
			}
			else {
				y=y+(var);
			}
		 Color color = new Color(image.getRGB(x,y));
		 R = color.getRed();
		 G = color.getGreen();
		 B = color.getBlue();
		 alpha = (R+G+B)/3;
		 if(alpha1-alpha>7 || alpha1-alpha<-7)
			 count++;
//3 подряд выходят за диапазон 
		 if(i>=2 && point[i-1]==count-1 && point[i-2]==count-2 && count>=3)
			 return false;
		point[i]=count;
		}
	return true;
	}

В результате этих манипуляций, ожидалось получить границы объекта, что позволило бы при наложении полученных рамок, при повторном проходе, выбрать объекты. Однако, метод рабочий, но подходит пожалуй лишь для детских разукрашек :) Если серьёзно, то вот результат работы этого кода (слева - оригинальное фото (с интернета); середина FloodFill с минимальным размером выбранной области >5 px; справа < 5 px):6390de522dec5147206842.jpeg
В реальности сегментация изображения выглядит немного иначе... Что я делаю не так? Как реализовать алгоритм сегментации или как улучшить написанное?
  • Вопрос задан
  • 126 просмотров
Пригласить эксперта
Ответы на вопрос 1
Griboks
@Griboks
Ничего не понятно. Какой метод вы используете? FloodFill просто выполняет заливку с допуском, поэтому позволяет выделять только более менее однородные области. У вас же на картинке всего 3 цвета, ещё и с большим разбросом.

оригинальное фото (с интернета)

Вам необходимо собрать целевой датасет, исходя из него выбрать подходящий метод. Если же проверять на рандомных картинках, то всегда можно найти неправильную сегментацию.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы