Przetwarzanie obrazów

0

Cześć mam spory problem(przynajmniej tak mi się wydaje). Piszę aplikację na Androida która ma przetwarzać zdjęcia tzn. nakładać filtry, powodować rozmycie zdjęcia i wiele innych. Nie mam większego problemu z operacjami punktowymi wszystko całkiem fajnie śmiga. Problem pojawia się gdy przechodzę do wykonywania operacji kontekstowych np. Blur. Czas odpowiedzi to od 5-10s do nawet 30-40s przy większej rozdzielczości. Troszkę czytałem tu i tam i zdaje się że to dla tego że w urządzeniu nie wystarcza cache i procesor musi odwoływać się do pamięci trwałej.
Chciałbym skrócić ten czas aby nie był dłuższy niż 1s.
Może znacie jakieś algorytmy lub biblioteki które mogły by mi pomóc, albo książki o przetwarzaniu wektorowym tablic czy coś w tym stylu.
Liczę na odpowiedz. Poniżej zamieszczam kod:

To śmiga ładnie:

public static Bitmap InverseImage(Bitmap bitmap){

			Bitmap alteredBitmap = Bitmap.CreateBitmap (bitmap.Width, bitmap.Height, bitmap.GetConfig ());
			Canvas canvas = new Canvas(alteredBitmap);
			Paint paint = new Paint();

			float[] colorMatrix_Negative = {
				-1.0f, 0, 0, 0, 255, //red
				0, -1.0f, 0, 0, 255, //green
				0, 0, -1.0f, 0, 255, //blue
				0, 0, 0, 1.0f, 0 //alpha
			};

			ColorFilter colorFilter_Negative = new ColorMatrixColorFilter (colorMatrix_Negative);

			paint.SetColorFilter(colorFilter_Negative);
			Matrix matrix = new Matrix();
			canvas.DrawBitmap(bitmap, matrix, paint);

			return alteredBitmap;
		}
 

A przy tym można sobie kawę dwa razy zaparzyć

 
public static Bitmap applyGaussianBlurEffect(Bitmap src) {
			float[] GaussianBlurConfig = new float[] {
				1, 2, 1,
				2, 4, 2,
				1, 2, 1 
			};
			ConvolutionMatrix convMatrix = new ConvolutionMatrix(3);
			convMatrix.applyConfig(GaussianBlurConfig);
			convMatrix.Factor = 16;
			convMatrix.Offset = 0;
			return ConvolutionMatrix.computeConvolution3x3(src, convMatrix);
		}

Klasa ConvolutionMatrix

public class ConvolutionMatrix
	{
		private static int size = 3;

		private float[] Matrix;
		public float Factor = 1;
		public float Offset = 1;

		public ConvolutionMatrix(int size){
			Matrix = new float[size * size];
		}

		public void applyConfig(float[] config) {
			Matrix = config;
		}

		public static Bitmap computeConvolution3x3(Bitmap src, ConvolutionMatrix matrix) {
			int width = src.Width;
			int height = src.Height;
			Bitmap result = Bitmap.CreateBitmap(width, height, src.GetConfig());

			int A, R, G, B;
			int sumR, sumG, sumB;
			int[] pixels = new int[size * size];


			for(int y = 0; y < height - 2; ++y) {
				for(int x = 0; x < width - 2; ++x) {

					// get pixel matrix
					for(int i = 0; i < size; ++i) {
						for(int j = 0; j < size; ++j) {
							pixels[i*j + j] = src.GetPixel(x + i, y + j);
						}
					}

					// get alpha of center pixel
					A = Color.GetAlphaComponent(pixels[4]);

					// init color sum
					sumR = sumG = sumB = 0;

					// get sum of RGB on matrix
					for(int i = 0; i < size; ++i) {
						for(int j = 0; j < size; ++j) {
							sumR += (Color.GetRedComponent(pixels[i*j + j]) * (int)matrix.Matrix[i*j + j]);
							sumG += (Color.GetGreenComponent(pixels[i*j + j]) * (int)matrix.Matrix[i*j + j]);
							sumB += (Color.GetBlueComponent(pixels[i*j + j]) * (int)matrix.Matrix[i*j + j]);
						}
					}

					// get final Red
					R = (int)(sumR / matrix.Factor + matrix.Offset);
					if(R < 0) { R = 0; }
					else if(R > 255) { R = 255; }

					// get final Green
					G = (int)(sumG / matrix.Factor + matrix.Offset);
					if(G < 0) { G = 0; }
					else if(G > 255) { G = 255; }

					// get final Blue
					B = (int)(sumB / matrix.Factor + matrix.Offset);
					if(B < 0) { B = 0; }
					else if(B > 255) { B = 255; }

					// apply new pixel
					result.SetPixel(x + 1, y + 1, Color.Argb(A, R, G, B));
				}
			}

			return result;
		}
		
	}
 
1

Na pewno można by popróbować z wielowątkowością, natomiast po prostu przetwarzanie takich rzeczy jak blur na CPU nie będzie wydajne.
Musiałbyś robić operacje na GPU albo poprzez OpenCL (nie wiem, jak sprawa tego wygląda na Androidzie), albo normalnie renderując zdjęcie i wykorzystując shadery.

Edit: możesz także zmienić algorytm na wydajniejszy (http://stackoverflow.com/questions/2067955/fast-bitmap-blur-for-android-sdk), ale to jest krótkowzroczne rozwiązanie (prędzej czy później natrafisz na taki algorytm, którego optymalizacja nie będzie łatwa/możliwa bez dobierania się do GPU tak czy siak).

0

Ok dzięki już się biorę za sprawdzanie.

1

Popełniłeś klasyczny błąd, który popełnia 99% studentów. Po pierwsze, używasz splotu w wersji dwuwymiarowej o złożoności O(n^2), zamiast separowalnych liniowo splotów 1D (złożoność O(2n)).

Jeżeli nie straszne są Ci publikacje naukowe, to sprawdź:

  1. Yang, Qingxiong, Kar-Han Tan, and Narendra Ahuja. "Real-time O (1) bilateral filtering." Computer Vision and Pattern Recognition, 2009. CVPR 2009. IEEE Conference on. IEEE, 2009.
  2. Porikli, Fatih. "Constant time O (1) bilateral filtering." Computer Vision and Pattern Recognition, 2008. CVPR 2008. IEEE Conference on. IEEE, 2008.

Poszukaj sobie też informacji o algorytmach overlap-save oraz overlap-add.

0

Dziękuję za odpowiedz, chętnie zajrzę do tych publikacji.

1 użytkowników online, w tym zalogowanych: 0, gości: 1