Author Topic: Как подсчитать количество определенного цвета в многоугольной области?  (Read 4947 times)

0 Members and 2 Guests are viewing this topic.

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Нужен совет, как подсчитать количество определенного цвета в многоугольной области. Область задана последовательностью координат Х,Y. Код на кликере или дельфи.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
А можешь это както показать визуально, хотябы примерн - что за многоугольник, и что за цвета (обьекты с какимто цветом скорее всего). многоугольник статичен или меняет форму со временем?

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
А че, интересно.
Code: (clickermann) [Select]
STRSEPARATE ("133,83,206,193,79,220,266,276,345,169,339,55,133,83", ",", $arr)  //координаты вершин. координаты первой и последней точки - равны



//опрелделяем границы
$y_max = $arr[1]       
$y_min = $arr[1]
$x_max = $arr[0]
$x_min = $arr[0]

FOR($i=3,$i<arrsize($arr),2)
   IF($y_max < $arr[$i])
      $y_max = $arr[$i]
   END_IF
   IF($y_min > $arr[$i])
      $y_min = $arr[$i]
   END_IF
   IF($x_max < $arr[$i-1])
      $x_max = $arr[$i-1]
   END_IF
   IF($x_min > $arr[$i-1])
      $x_min = $arr[$i-1]
   END_IF
   
END_CYC



//закрашиваем буфер нулем

PXLREPLACE(0,0,500,500, -1, 0)

//рисуем единицами
FOR($i=0,$i<arrsize($arr)-2,2)
   
   $x1 = $arr[$i]
   $y1 = $arr[$i+1]
   $x2 = $arr[$i+2]
   $y2 = $arr[$i+3]
   
   
   $n = ($y2-$y1)/abs($y2-$y1)
   FOR($y=$y1,$y!$y2+$n,$n)
      $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 1)
   end_cyc
   
   
END_CYC

//SCREENSHOTEX(0,0,500,500, "Image_", 0)


//закрашиваем все что в нутри многоугнольникам с помощью оператора XOR   pxl($x,$y) xor pxl($x+1,$y)
FOR($y=$y_min+1,$y<$y_max)
   FOR($x=$x_min,$x<$x_max)
      pxlreplace($x+1,$y,$x+1,$y, -1, pxl($x,$y) xor pxl($x+1,$y) )
   END_CYC
END_CYC

//то что получили, перекрашиваем в нужные цвета.
PXLREPLACE(0,0,500,500, 0, 16777215)
SCREENSHOTEX(0,0,500,500, "Image_", 0)


halt


//это наглядный пример с последующим получением массива всех точек в многоугольнике с помощью сканпиксела. нУ И ПООЧЕРЕДИ ПРОВЕРЯТЬ КАЖДУЮ КООРДИНАТУ НА ИСКОМЫЙ ЦВЕТ

//НО МОЖНО ПЕРЕДЕЛАТЬ БЕЗ ГРАФИЧЕСКОГО БУФЕРА, НАПРЯМУЮ СОЗДАВАТЬ МАССИВ КООРДИНАТ. И ДАЛЬЕ УЖЕ ЦИКЛ ПРОВЕРКИ ЭТИХ ПИКЧЕЛЕЙ НА ИСКОМЫЙ

Возможны ошибки, вечером подробнее проверю. Инфа отсюда https://habr.com/post/116398/ .

Результат из кода выше:

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Паскаль у меня был 20 лет назад и мозг не такой гибкий, как раньше. Играть уже не очень интересно, в свободное время пишу бота, что бы вместо меня играл в линейку.

Большинство данных берется из памяти клиента. В ручную задаются координаты зоны охоты и маршрут внутри нее, если нет мобов. У внутриигровой команды /targetnext радиус действия маленький. Как это обойти я нашел, теперь можно брать ближайшего по заданному списку в пределах видимости клиентом. Но между ботом и мобом могут быть препятствия. Соответственно если между ними нет белого цвета можно брать в таргет и бежать напрямую, если есть продолжаем бег по заданному маршруту.

На рисунке точка 1 = бот, 2 и 3 - мобы. Внутри желтой области  бот охотится на мобов.

В кликере есть функция для прямоугольной области PXLCOUNT (x, y, x2, y2, color). Мне же нужен многоугольник.



ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Если между 1 и 2 точками нет белого цвета атакуем. Между 1 и 3 есть белый цвет не атакуем. На зеленые полосы не обращаем внимания, они нарисованы позже, для наглядности.

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Бот бегает по заданному маршруту внутри желтой области. Мобы нужны не все и только внутри заданной области. Физические размеры бота и моба больше точки, плюс есть еще камера от 3 лица которая вблизи стен начинает тупить, что вносит искажения в расчеты угла поворота.
Поэтому считаем количество белого цвета в 4х угольнике между ботом и мобом. Если 0 то можно брать в таргет и атаковать. Персонаж автоматически бежит по прямой к мобу. Если больше 0, то или этот моб вне желтой зоны или есть препятствия, продолжаем бежать по маршруту пока между ботом и мобом не будет белого цвета.

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Действительно, задача одна, а просишь другое.
По словесному описанию понятно, я даже делал такое в боте для TimeZero, правда там гексы.
И ходил не очень оптимально, но там так и нужно было, т.к. дальность действия оружия не маленькая.

1. Вычисляем азимут на ближайшего моба, это же предпочитаемый азимут движения.
2. Пока не важно есть прямой путь к мобу или нет. Есть определённый выбранный оптимальный радиус при достижении которого начинаем искать обход.
3. Проверяем на линии между персом и мобом нет ли препятствий (стен) ближе, чем заданное расстояние.
4. Если препятствие есть идём на моба...
5. Пока расстояние до препятствия больше размера радиуса из п.2 идём на моба
6. Если равно или меньше ищем обходной путь...
   6.1 От выбранного направления на расстоянии радиуса из п.2 проверяем точки на окружности со сдвигом в N градусов поочерёдно в обе стороны.
    Т.е. на 5 градусов левее направления преведущего движения, на 5 правее, на 10 левее, на 10 правее и т.д. пока не всретим открытое место.
   6.2 Вычисляем новый азимут движения, на новую точку. Берём чуть запас в ту же сторону чтоб не идти впритирку.
   6.3 Пока идём в этом направлении проверяем не открылся ли из текущей точки прямой путь.


ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Мне только подсчет цветов, остальное я уже сделал.

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Хм. Ты так и не объяснил, зачем здесь считать цвета?


ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Не важно сколько желтых, важно что-бы белых не было.

Пример во вложении
« Last Edit: October 12, 2018, 06:43:26 PM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
И действительно, можно было както попроще все это замутить. Да хотябы тем же уровненией прямой, если одной линии пикселей мало, то можно с несколькими сдвигами.

Но, раз уж я там выше накалякал эти ненужные сложные расчеты, то вот на твоем рисунке прямо с браузера с колормодом №6.
Code: (текст) [Select]
19:26:46 start
19:27:04 в нашей области 3268 белых пикселей
19:27:05 в нашей области 1312 зеленых пикселей
19:27:06 в нашей области 808 желтых пикселей
19:27:06 а всего в нашей области 16354 пикселей
всегото 20 секунд  ;D, но и размеры твоей картинки не маленькие...

Code: (clickermann) [Select]
print("start")

$allx1 = 508     //координаты твоего рисунка
$ally1 = 814
$allx2 = 2039
$ally2 = 1675



STRSEPARATE ("819,1592,1020,1117,1035,1119,834,1600,819,1592", ",", $arr)  //координаты вершин. координаты первой и последней точки - равны



//опрелделяем границы
$y_max = $arr[1]
$y_min = $arr[1]
$x_max = $arr[0]
$x_min = $arr[0]

FOR($i=3,$i<arrsize($arr),2)
   IF($y_max < $arr[$i])
      $y_max = $arr[$i]
   END_IF
   IF($y_min > $arr[$i])
      $y_min = $arr[$i]
   END_IF
   IF($x_max < $arr[$i-1])
      $x_max = $arr[$i-1]
   END_IF
   IF($x_min > $arr[$i-1])
      $x_min = $arr[$i-1]
   END_IF
   
END_CYC



//закрашиваем буфер нулем

PXLREPLACE($allx1,$ally1,$allx2,$ally2, -1, 0)

//рисуем единицами
FOR($i=0,$i<arrsize($arr)-2,2)
   
   $x1 = $arr[$i]
   $y1 = $arr[$i+1]
   $x2 = $arr[$i+2]
   $y2 = $arr[$i+3]
   
   
   $n = ($y2-$y1)/abs($y2-$y1)
   FOR($y=$y1,$y!$y2+$n,$n)
      $x = ROUND((($x1*$y2-$x2*$y1)+($x2-$x1)*$y)/($y2-$y1),0)
      PXLREPLACE ($x,$y,$x,$y, -1, 1)
   end_cyc
   
   
END_CYC




//закрашиваем все что в нутри многоугнольникам с помощью оператора XOR   pxl($x,$y) xor pxl($x+1,$y)
FOR($y=$y_min+1,$y<$y_max)
   FOR($x=$x_min,$x<$x_max)
      pxlreplace($x+1,$y,$x+1,$y, -1, pxl($x,$y) xor pxl($x+1,$y) )
   END_CYC
END_CYC

//то что получили, перекрашиваем в нужные цвета.
PXLREPLACE($allx1,$ally1,$allx2,$ally2, 0, 16777215)
SCREENSHOTEX($allx1,$ally1,$allx2,$ally2, "Image_", 0)


SCANPXL($var, $allx1,$ally1,$allx2,$ally2, 1)   // создаем массив координат каждой точки нашего многоугольника



GETSCREEN   //обновляем наш испорченный буфер
COLORMODE(6) //так как в оригинале jpg, делаем цвета почетче


FOR($i=0,$i<arrsize($var), 2)
   
   IF(pxl($var[$i],$var[$i+1]) = 16777215)
      inc($n_pix)
   END_IF
   
END_CYC

print("в нашей области ",$n_pix," белых пикселей")
$n_pix = 0

FOR($i=0,$i<arrsize($var), 2)
   
   IF(pxl($var[$i],$var[$i+1]) = 4194239)
      inc($n_pix)
   END_IF
   
END_CYC

print("в нашей области ",$n_pix," зеленых пикселей")
$n_pix = 0

FOR($i=0,$i<arrsize($var), 2)
   
   IF(pxl($var[$i],$var[$i+1]) = 4194303)
      inc($n_pix)
   END_IF
   
END_CYC


print("в нашей области ",$n_pix," желтых пикселей")


print("а всего в нашей области ", arrsize($var)," пикселей")

halt

Во вложении черным отмечена та область которая сканировалась (относительно всего рисунка).



ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Не взлетит. Там опрашивать надо хотя бы 1 раз в секунду. Буду думать.

зы Картинка сжата раз в 5.
« Last Edit: October 12, 2018, 08:10:47 PM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
зы Картинка сжата раз в 5.
:o раз в пять?
Разрешение твоей картинки 1533х864, если это умножить на пять, то это уже даже в рамки 4К не влазит.

Но это не важно, на скорость выполнения влияет только границы искомой области, это x_min - y_min -  x_max  - y_max  . В твоем примере это примерно 220х480 точек, размер не маленький.

Но и это не важно, нужно искать более подходящий и простой принцип работы для такой задачи. Как вариант, я писал выше, уровнение прямой - тупо проверяешь линию пикселей от бота к мобу. Если этого мало, то можно проверить по тойже прямой но со смещением (право лево либо верх низ). Либо попробуй вариант что предложил Vint, я сильно не вникал в его суть...

Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Человек отказался, уже всё сделано. Осталось подсчитать цвета. Вот только считать их и не надо, что я и пытался донести.
Здесь нужно придумать способ чтобы было просто и быстро. Способ я давно уже придумал, тогда ещё. А начинал тоже с подсчёта, потом с поиска, там такие ужасные количества получались...
На самом деле можно проверять несколько раз в секунду в зависимости от размеров. И даже уравнение прямой не нужно, там нужно другое уравнение.

Могу дать направление. Видите, у нас обширные области, места полно. И нам к мобу не по канату идти над пропастью, такая точность не нужна.
« Last Edit: October 12, 2018, 10:29:36 PM by Vint »


Vint

  • Супермодератор
  • Герой форума
  • *
  • Posts: 3935
  • Лечу куда хочу. cman 4.13.014x32, 4.14.003 W10
    • View Profile
Можно и по уравнению прямой проверить, тоже нормально. Только взять две прямые чуть левее и чуть правее если линия ближе к вертикальной. Можно проверять не каждый пиксел, а с шагом. Шаг можно взять чуть меньше, чем расстояние которое мы сдвинули линию. Ведь там нет уж очень острых углов. Может и больше можно.