2016-08-30 3 views
0

Мне нужно изменить определенный цвет PNG, хранящийся в SDCard. Я не могу использовать tintcolor над растровым изображением или над любым другим объектом, потому что это закрасит все изображение, а не определенный цвет пикселя.Каков наилучший способ изменить цвет пикселя png на пиксель на Android?

Зачем мне это нужно?
Я пытаюсь разработать приложение аватара, и я хочу, чтобы иметь возможность изменить волосы аватара любым цветом, который я выбираю из палитры. Эти волосы имеют два цвета: один для границы, а другой для остальных волос. Я просто хочу изменить цвет воздуха и сохранить границу.

Это простой случай, но на изображении может быть более одного цвета.

Я искал решение. Это единственное, что я нашел (meaby там может быть больше, но я не повезло):

Android Bitmap: Convert transparent pixels to a color

И это то, что он подвергается там:

Bitmap b = ...; 
for(int x = 0; x<b.getWidth(); x++){ 
    for(int y = 0; y<b.getHeight(); y++){ 
     if(b.getPixel(x, y) == Color.TRANSPARENT){ 
      b.setPixel(x, y, Color.WHITE); 
     } 
    } 
} 

Я хочу знать, если есть лучший способ сделать это. Что-то вроде:

bipmapImage.changeColor(originalColor, newColor); 

Я не знаю, если с помощью цикла, чтобы проверить пиксель пиксель является хорошим показателем. Представьте себе изображение 1080 x 1080.

Заранее спасибо.

+0

Вы используете прозрачность, чтобы указать, какие пиксели являются волосами? – samgak

+0

Вам лучше использовать API-интерфейсы OpenCV Matrix, особенно для производительности (и компактности). –

+0

@samgak Я не использую прозрачность, потому что я могу менять несколько цветов на одном изображении. –

ответ

2

Вы можете получить более высокую производительность по сравнению с getPixel() и setPixel() по телефону copyPixelsToBuffer(), чтобы скопировать пиксели в буфер, затем изменить значения пикселов в буфере, и, наконец, вызывая copyPixelsFromBuffer() скопировать из буфера обратно в растровом изображении:

boolean changeColor(Bitmap bitmap, int originalColor, int newColor) 
{ 
    // bitmap must be mutable and 32 bits per pixel: 
    if((bitmap.getConfig() != Bitmap.Config.ARGB_8888) || !bitmap.isMutable()) 
     return false; 

    int pixelCount = bitmap.getWidth() * bitmap.getHeight(); 
    IntBuffer buffer = IntBuffer.allocate(pixelCount); 
    bitmap.copyPixelsToBuffer(buffer); 
    int[] array = buffer.array(); 
    for(int i = 0; i < pixelCount; i++) 
    { 
     if(array[i] == originalColor) 
      array[i] = newColor; 
    } 
    bitmap.copyPixelsFromBuffer(buffer); 

    return true;  
} 

Однако есть дополнительные осложнения: растровое изображение необходимо использовать формат ARGB_8888 пикселя (если он отличается вам нужно будет писать дополнительный код для обработки этого), и вам нужно поймать за исключением памяти, которые могут возникнуть при распределении IntBuffer. Сначала вы должны профилировать код с помощью setPixels() и посмотреть, неприемлема ли скорость.

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

+0

Сделайте свой пример, но получите изображение другого цвета, вместо ожидаемого, как вы думаете, в чем причина? –

+0

@ Сергей наиболее вероятной причиной является порядок rgba в вашей стоимости int отличается от того, что ожидает Android Bitmap. Цвет должен быть сформирован следующим образом: int color = (a << 24) | (r << 16) | (г << 8) | б; Где r g b находится в диапазоне 0-255. См. Здесь для получения дополнительной информации: https://developer.android.com/reference/android/graphics/Color.html – samgak

1

Лучше использовать OpenCV Матричные API, особенно для производительности (и компактности).

Проверка OpenCV Учебник для Android here.

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

(Вы должны понимать функцию Mat первый.)

На самом деле я не использовал OpenCV с Android.
Вот некоторые примеры кодов, чтобы изменить цвет волос на красный C++:

// 1. Loading 
Mat src = imread("yourImagePath/yourOriginalImage.jpg"); // This code will automatically loads image to Mat with 3-channel(BGR) format 
Mat mask = imread("yourImagePath/yourHairMaskImage.png", CV_GRAYSCALE); // This code will automatically loads mask image to Mat with 1-channel(grayscale) format 

// 2. Splitting RGB channel into 3 separate channels 
vector<Mat> channels; // C++ version of ArrayList<Mat> 
split(src, channels); // Automatically splits channels and adds them to channels. The size of channels = 3 

// 3-1. Adjusting red color 
Mat adjustRed = channels[0]*1.5; 

// 3-2. Copy the adjusted pixels into org Mat with mask 
channels[2] = adjustRed & mask + channels[0] & ~mask; 

// 4. Merging channels 
Mat dst; 
merge(channels, dst); // dst is re-created with 3-channel(BGR). 
// Note that OpenCV applies BGR by default if your array size is 3, 
// even if actual order is different. In this case this makes sense. 

// 5. Saving 
imwrite("yourImagePath/yourDstImage.jpg", dst); 


код Android версия будет не отличается, я думаю.

+0

Я принимаю ответ Самгака (пока), потому что это прямой способ сделать то, что я хочу. Я оцениваю ваши, может быть, моя идея не так точно, как вы показали, но ваша идея может быть хорошей, как начать, и это может быть лучшим способом говорить о производительности. Спасибо за все. –