как генерировать цветовую гистограмму изображения RGB?

Чтобы описать это, сначала давайте понять, как хранятся локальные переменные и объекты.

Локальная переменная хранится в стеке: enter image description here [/g1]

Если вы посмотрели на изображении вы должны понимать, как все работает.

Когда вызов функции вызывается Java-приложением, стек стека выделяется в стеке вызовов. Фрейм стека содержит параметры вызываемого метода, его локальные параметры и обратный адрес метода. Адрес возврата обозначает точку выполнения, из которой выполнение программы должно продолжаться после возврата вызванного метода. Если нет места для нового стека кадров, то StackOverflowError вызывается виртуальной машиной Java (JVM).

Наиболее распространенным случаем, который может исчерпать стек Java-приложения, является рекурсия. В рекурсии метод запускается во время его выполнения. Рекурсия рассматривается как мощный метод программирования общего назначения, но ее следует использовать с осторожностью, чтобы избежать StackOverflowError.

Пример, показывающий StackOverflowError, показан ниже:

StackOverflowErrorExample.java:

public class StackOverflowErrorExample {

    public static void recursivePrint(int num) {
        System.out.println("Number: " + num);

        if(num == 0)
            return;
        else
            recursivePrint(++num);
    }

    public static void main(String[] args) {
        StackOverflowErrorExample.recursivePrint(1);
    }
}

В этом примере мы определяем рекурсивный метод, называемый recursivePrint, который печатает целое число, а затем вызывает себя со следующим последовательным целым числом в качестве аргумента. Рекурсия заканчивается, пока мы не перейдем в 0 в качестве параметра. Однако в нашем примере мы передали параметр из 1 и его увеличивающих последователей, следовательно, рекурсия никогда не завершится.

Пример выполнения с использованием флага -Xss1M, который определяет размер стека потоков ниже 1MB, показано ниже:

Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
        at java.io.PrintStream.write(PrintStream.java:480)
        at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
        at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
        at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
        at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
        at java.io.PrintStream.write(PrintStream.java:527)
        at java.io.PrintStream.print(PrintStream.java:669)
        at java.io.PrintStream.println(PrintStream.java:806)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
        ...

В зависимости от начальной конфигурации JVM результаты могут отличаться, но в конечном итоге следует вызывать StackOverflowError. Этот пример является очень хорошим примером того, как рекурсия может вызвать проблемы, если не выполнять их с осторожностью.

Как работать с StackOverflowError

  1. Простейшим решением является тщательная проверка трассировки стека и обнаружение повторяющегося шаблона номеров строк. Эти номера строк указывают, что код рекурсивно называется. Как только вы обнаружите эти строки, вы должны тщательно проверить свой код и понять, почему рекурсия никогда не заканчивается.
  2. Если вы подтвердили правильность реализации рекурсии, вы можете увеличить размер стека, чтобы разрешить большее количество вызовов. В зависимости от установленной виртуальной машины Java (JVM) размер стека по умолчанию может равняться либо 512 КБ, либо 1 МБ. Вы можете увеличить размер стека потоков, используя флаг -Xss. Этот флаг можно указать либо через конфигурацию проекта, либо через командную строку. Формат аргумента -Xss: -Xss<size>[g|G|m|M|k|K]
0
задан Lynx 13 July 2018 в 21:02
поделиться

1 ответ

Способ 1:

{k:np.sum(a==k) for k in set(a.ravel().tolist())}

или немного более читаемо

count = lambda A, key : np.sum(A==key)
unique_keys = set(A.ravel().tolist())
return {key : count(A,key) for key in unique_keys}

Прогулка по нему:

{...}

для генерации отображения

set(a.ravel().tolist())

a.ravel выравнивает изображение ; в списке, он может быть передан в набор , который является контейнером для уникальных элементов.

np.sum(a==k)

Подсчитайте, сколько раз элемент находится на изображении. Этот не самый эффективный способ сделать это , но помещает гистограмму в запрошенный вами формат


Взятые вместе, если ваше изображение 3x3

a = np.array([[1,2,3],[1,3,3],[3,3,3]])

, затем

set(a.ravel().tolist()) # yields set([1, 2, 3])

, и все выражение дает

{1: 2, 2: 1, 3: 6}

Способ 2

from PIL.Image import fromarray
b = fromarray(a.astype(np.uint8)) # convert to a PIL image
hist =  {idx:count for idx, count in enumerate(b.histogram()) if count}

Это работает очень аналогично (используя понимание словаря), но использует функциональность гистограммы PIL , а перечисляет для извлечения индексов.

«Binning»

Если вы хотите иметь «бункеры» цветов, как вы указали, то оставшаяся работа просто определяет структуру вашего бина, что будет сделано многими способами. Например, в предыдущем примере мы можем создавать фиксированные ячейки с фиксированным размером

num_bins = 2
b = fromarray(a.astype(np.uint8)//num_bins) # convert to a PIL image, binned
hist =  {idx*num_bins:count for idx, count in enumerate(b.histogram()) if count}
1
ответ дан en_Knight 17 August 2018 в 12:08
поделиться
  • 1
    Извините за ответ так поздно. Спасибо за ответ. Но здесь вы создали только словарь с индексом от 0 до 784, чего я не хотел. Потому что это только сглаженное количество для подсчета интенсивности каждого канала. Я хочу сгруппировать цветовое пространство в меньшее подпространство, от 256 x 256 x 256 до 100 цветовых категорий. И получить распределение цветов в этих 100 категориях (мы можем определить категорию цвета кубом в цветовом пространстве, скажем, с шириной, высотой, длиной 10 на 10 на 10). Я предполагаю, что в этом смысле его нельзя было бы назвать цветной гистограммой в обычном смысле. – jack 16 July 2018 в 16:29
  • 2
    @jack это нормально, редактирует ли адрес вашего вопроса? – en_Knight 16 July 2018 в 17:22
  • 3
    извините, но я боюсь, что не ..... Когда вы разделили num_bins, я думаю, вы разделили только каждое значение массива. Это не делает ящик, я думаю ... – jack 16 July 2018 в 17:33
  • 4
    @jack hmm Я думаю, что это делает :) Вы попробовали это на примере? Если ваш входной массив был [1,2,3,4,5], и вы делите на 2, используя целочисленное деление, вы получите [0,1,1,2,2]; они теперь привязаны к размеру 2. Алгоритм правильно интерпретирует, что в [4, 6] есть два элемента из [2,4] и два элемента из bin [0,2). Как я уже сказал, существует много способов возможного сделать биннинг, но это очень распространенный – en_Knight 16 July 2018 в 17:37
  • 5
    Понимаю. Но я боюсь, что он по-прежнему относится только к значениям интенсивности из разных каналов, не так ли? Так что, если я хочу генерировать случайный цвет на основе гистограммы, которую вы дали, я бы мог только пробовать из каждого канала самостоятельно и конкатенировать их вместе? – jack 16 July 2018 в 17:53
Другие вопросы по тегам:

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