Использование get () и put () для доступа к значениям пикселей в OpenCV для Java

Я новичок в использовании OpenCV для JAVA. Я хочу получить доступ к отдельным значениям пикселей матрицы изображения. С тех пор JAVA JAR для OpenCV не делаетНе предлагая хороших функций, таких как C ++, я столкнулся с некоторыми проблемами. После долгих поисков я нашел два разных способа сделать это, хотя они не объяснены должным образом (даже в документации). Мы можем сделать это либо используя функции get () и put (), либо преобразовав данные mat в примитивный тип java, такой как массивы. Я пробовал оба, но получал разные результаты! Пожалуйста, помогите объяснить, что я делаю не так. Я использую их неправильно или какую-то другую глупую проблему. Я все еще новичок, поэтому, пожалуйста, прости, если это глупый вопрос. :)

Случай 1: Использование функции get ()

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image
Mat C = A.clone();
Size sizeA = A.size();
for (int i = 0; i < sizeA.height; i++)
    for (int j = 0; j < sizeA.width; j++) {
        double[] data = A.get(i, j);
        data[0] = data[0] / 2;
        data[1] = data[1] / 2;
        data[2] = data[2] / 2;
        C.put(i, j, data);
    }

Случай 2: Использование массива

Mat A = Highgui.imread(image_addr); \\"image_addr" is the address of the image
Mat C = A.clone();
int size = (int) (A.total() * A.channels());
byte[] temp = new byte[size];
A.get(0, 0, temp);
for (int i = 0; i < size; i++)
   temp[i] = (byte) (temp[i] / 2);
C.put(0, 0, temp);

Теперь, насколько я понимаю, они оба должны делать то же самое. Они оба получают доступ к значениям отдельных пикселей (все 3 канала) и делают его наполовину. Я не получаю ошибки после запуска. Но полученное изображение в этих двух случаях отличается. Может кто-нибудь объяснить, в чем проблема? Может быть я неt точно понять, как работает функция get ()? Это из-за приведения типа byte ()? Пожалуйста помоги.

Спасибо!

Ответы на вопрос(2)

Решение Вопроса

тового изображения во втором случае на * CV_64FC3 *, чтобы я мог использовать double [] вместо byte [], и это решило проблему.

Mat A = Highgui.imread(image_addr); //"image_addr" is the address of the image
Mat C = A.clone();
A.convertTo(A, CvType.CV_64FC3); // New line added. 
int size = (int) (A.total() * A.channels());
double[] temp = new double[size]; // use double[] instead of byte[]
A.get(0, 0, temp);
for (int i = 0; i < size; i++)
   temp[i] = (temp[i] / 2);  // no more casting required.
C.put(0, 0, temp);

К вашему сведению, я также провел некоторые измерения времени, и использование второго метода намного быстрее, чем первого.

 gargsl29 апр. 2015 г., 10:19
@rmaik У каждого канала естьs собственные значения интенсивности (красный, синий или зеленый) для каждого пикселя. Таким образом, общее количество этих значений интенсивности в изображении равно числу пикселей * общее количество каналов. Таким образом, в этом случае total () дает вам общее количество пикселей в изображении, а channel () дает вам количество каналов.
 rmaik25 мар. 2015 г., 18:11
спасибо за хороший вопрос, можете ли вы объяснить, почему вы использовали: (A.total () * A.channels ()); ?? total (метод возвращает высоту withd *, почему вы умножены на номера каналов, я знаю, что изображение RGB имеет 3 канала ... но мне нужно больше пояснений, пожалуйста

Нашел простое и рабочее решение после долгих поисков

Mat img = Highgui.imread("Input.jpg"); //Reads image from the file system and puts into matrix
int rows = img.rows(); //Calculates number of rows
int cols = img.cols(); //Calculates number of columns
int ch = img.channels(); //Calculates number of channels (Grayscale: 1, RGB: 3, etc.)

for (int i=0; i<rows; i++)="" {="" for="" (int="" j="0;" j<cols;="" j++)="" double[]="" data="img.get(i," j);="" stores="" element="" in="" an="" array="" k="0;" <="" ch;="" k++)="" runs="" the="" available="" number="" of="" channels="" data[k]="data[k]" *="" 2;="" pixel="" modification="" done="" here="" }="" img.put(i,="" j,="" data);="" puts="" back="" into="" matrix="" highgui.imwrite("output.jpg",="" img);="" writes="" image="" to="" file="" system="" using="" values="" modified="" code=""></rows;>

<strong>Замечания:</strong> Важным моментом, который нигде не упоминался в Интернете, является то, что метод<code>put</code> не записывает пиксели на<code>Input.jpg</code>, Это просто обновляет значения матрицы<code>img</code>, Поэтому приведенный выше код ничего не меняет во входном изображении. Для получения видимого вывода, матрица<code>img</code> должен быть записан в файл, т.е.<code>Output.jpg</code> в этом случае. Кроме того, используя<code>img.get(i, j)</code> Похоже, что это лучший способ обработки матричных элементов, а не использование принятого решения, описанного выше, поскольку это помогает лучше визуализировать матрицу изображения и работать с ней и не требует большого выделения непрерывной памяти.

 RenaudBlue24 авг. 2016 г., 15:55
Это работает, но очень очень медленно. Может занять 30 секунд для 8-мегапиксельного изображения на хорошем компьютере. Вместо этого вы хотите прочитать все данные одновременно в буфере, используя Mat.get (0,0, byte [totalNumberOfPixel * bytesPerPixel])

Ваш ответ на вопрос