Для выделения области на изображении в цветовом диапазоне, я использую матрицу 3x3. В позиции
x,y производится выборка
последующих координат (
a,b,c,d), куда будет сдвинут крестик, с предварительной проверкой диапазона. То есть в первой точке (x,y) берутся цветовые параметры для a,b,c,d. А именно: Вычисляется альфа-канал и, пожалуй на этом всё.. Если например
С выходит за пределы диапазона взятого в первоначальной точке (x,y), то для
С делаются ещё шаги в право и проверяется, не один ли это писксель выбился с диапазона?
Программно это выглядит следующим образом: Берём параметры в позиции 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):
В реальности
сегментация изображения выглядит немного иначе... Что я делаю не так? Как реализовать
алгоритм сегментации или как улучшить написанное?