Pixelizacja obrazu

0

Witam. Początkowo pytałem się jak zrobić filtr na pixelizacje obrazu (mosaic/pixelate)... ale juz sam do tego doszedłem i wydaje mi się, że warto byłoby utworzyć w tym dziale temat z różnymi algorytmami itp. Dlatego też zamieszczam filtr na pixelizacje:

Tak to wygląda w praktyce: SetMosaic (5) ;

user image

Małe objaśnienie do kodu:

  1. Funkcja jest składową klasy image, pisanej przeze mnie... Klasa ta przechowuje szerokość, wysokość obrazka (iWidth, iHeight) oraz wskaznik do bitów obrazka (pImage). Każdy pixel obrazka jest zapisywany na 32 bitach (RGBA = 8 bitów - czerwony, 8 bitów - zielony, 8 bitów - niebieski, 8 bitów - kanał przezroczystości)

  2. W zmiennych iR, iG, iB, iA są przechowywane sumy odpowiednio czerwonej, zielonej, niebieskiej, "alpha" barwy z jednej komórki. Wielkość komórki określa parametr funkcji iCell, i tak jeśli będzie równy 4. To zmienne iR, iG... będą przechowywały sumę barw z czterech kolejnych pixeli. Następnie obliczana jest średnia tych pixeli i taka średnia jest zapisywana do całej komórki czyli do obrazka o wielkości 4 x 4 px. Filt uwzględnia też tzw. komórki ucięte. Czyli jeśli obraz miał 300 x 300 px, a iCell zostało ustawione na 7 to 300 / 7 daje nam 42 i jeszcze 6 pixeli. Tak więc dla krańcowych komórek jest wykonywana oddzielna operacja na obliczanie średniej barwy pixela. Suma barw 6 pixeli nie jest dzielona na 7 a na 6 (średnia arytmetyczna)...

Tyle wyjaśnienia chyba wystarczy... pozdrawiam :)

/*______________
   Filtr mosaic
  ______________*/

BOOL image::SetMosaic (int iCell)
{
	// Wartość bezwzględna z wielkości komórki

	if (iCell < 0)
	{
		iCell *= -1 ;
	}

	// Ustawienie wskaźnika i zmiennych przechowujacych sumę barw

	RGBA * rgba = (RGBA *) pImage ;

	int iR = 0 ;
	int iG = 0 ;
	int iB = 0 ;
	int iA = 0 ;

	// Poziomy przebieg pętli

	for (int y = 1; y <= iHeight; y++)
	{
		for (int x = 1; x <= iWidth; x++, rgba++)
		{
			iR += rgba->rgbaR ;
			iG += rgba->rgbaG ;
			iB += rgba->rgbaB ;
			iA += rgba->rgbaA ;

			if (x % iCell == 0)
			{
				iR = iR / iCell ;
				iG = iG / iCell ;
				iB = iB / iCell ;
				iA = iA / iCell ;

				for (int i = 0; i < iCell; i++)
				{
					rgba->rgbaR = iR ;
					rgba->rgbaG = iG ;
					rgba->rgbaB = iB ;
					rgba->rgbaA = iA ;

					rgba-- ;
				}

				rgba += iCell ;

				iR = 0 ;
				iG = 0 ;
				iB = 0 ;
				iA = 0 ;
			}
			else if (x == iWidth)
			{
				iR = iR / (iWidth % iCell) ;
				iG = iG / (iWidth % iCell) ;
				iB = iB / (iWidth % iCell) ;
				iA = iA / (iWidth % iCell) ;

				for (int i = 0; i < iWidth % iCell; i++)
				{
					rgba->rgbaR = iR ;
					rgba->rgbaG = iG ;
					rgba->rgbaB = iB ;
					rgba->rgbaA = iA ;

					rgba-- ;
				}

				rgba += iWidth % iCell ;

				iR = 0 ;
				iG = 0 ;
				iB = 0 ;
				iA = 0 ;
			}
		}

		iR = 0 ;
		iG = 0 ;
		iB = 0 ;
		iA = 0 ;
	}

	// Pionowy przebieg pętli

	for (int x = 1; x <= iWidth; x++)
	{
		rgba = (RGBA *) pImage ;
		
		iR = 0 ;
		iG = 0 ;
		iB = 0 ;
		iA = 0 ;

		rgba += x - 1 ;

		for (int y = 1; y <= iHeight; y++, rgba += iWidth)
		{
			iR += rgba->rgbaR ;
			iG += rgba->rgbaG ;
			iB += rgba->rgbaB ;
			iA += rgba->rgbaA ;

			if (y % iCell == 0)
			{
				iR = iR / iCell ;
				iG = iG / iCell ;
				iB = iB / iCell ;
				iA = iA / iCell ;

				for (int i = 0; i < iCell; i++)
				{
					rgba->rgbaR = iR ;
					rgba->rgbaG = iG ;
					rgba->rgbaB = iB ;
					rgba->rgbaA = iA ;

					rgba -= iWidth ;
				}

				rgba += iWidth * iCell ;

				iR = 0 ;
				iG = 0 ;
				iB = 0 ;
				iA = 0 ;
			}
			else if (y == iHeight)
			{
				iR = iR / (iHeight % iCell) ;
				iG = iG / (iHeight % iCell) ;
				iB = iB / (iHeight % iCell) ;
				iA = iA / (iHeight % iCell) ;

				for (int i = 0; i < iHeight % iCell; i++)
				{
					rgba->rgbaR = iR ;
					rgba->rgbaG = iG ;
					rgba->rgbaB = iB ;
					rgba->rgbaA = iA ;

					rgba -= iWidth ;
				}

				rgba += iWidth * (iHeight % iCell) ;

				iR = 0 ;
				iG = 0 ;
				iB = 0 ;
				iA = 0 ;
			}
		}
	}

	return TRUE ;
}

dorzycam jeszcze deklaracje funkcji i struktury RGBA

#include <windows.h>

#define COLOR      0
#define COLORALPHA 1

typedef struct tagRGBA
{
	BYTE rgbaB ;
	BYTE rgbaG ;
	BYTE rgbaR ;
	BYTE rgbaA ;
} RGBA ;

class image
{
public:
	BYTE * pImage ;
	int    iWidth ;
	int    iHeight ;
	BYTE * LoadImageFromFile (PTSTR pstrFileName) ;
	BYTE *         GetScreen (HWND hwnd, int xPos, int yPos) ;

	BOOL    SetImageFromFile (TCHAR * szFileName, TCHAR * szExtension) ;
	BOOL  SetImageFromBitmap (HBITMAP hBitmap) ;

	BOOL            SetAlpha (image * pImage) ;

	BOOL        SetGreyscale (void) ;
	BOOL           SetInvert (void) ;
	BOOL       SetBrightness (int iBrightness) ;
	BOOL     SetColorBalance (int iRed, int iGreen, int iBlue) ;
	BOOL            SetSepia (void) ;
	BOOL         SetSolarize (void) ;
	BOOL           SetMosaic (int iCell) ;
	BOOL        SetPixelRGBA (int xPos, int yPos, BYTE bRed, BYTE bGreen, BYTE bBlue, BYTE bAlpha) ;
	RGBA        GetPixelRGBA (int xPos, int yPos) ;

	BOOL             Display (HWND hwnd, int xPos, int yPos, int iFlag) ;
	~image()
	{
		delete pImage ;
	}
} ;

</image>
0

heh
i to się nazywa wyższy język programowania
w asmie napisałbym to krócej ;P

0
V-tec napisał(a)

heh
i to się nazywa wyższy język programowania
w asmie napisałbym to krócej ;P
Co Cię powstrzymuje? Napisz - podziel się z innymi.

0

kiepskie miejsce, lepiej wrzucic to do faq

0

Naprawde wqrzaja mnie tacy ludzie, nie dość że dzielę się swoim kodem to jeszcze tego typu komentarze "ja bym to napisał lepiej" - jak jesteś taki dobry to sobie napisz i to zamiesc a jesli nie chcesz zamiescic to lepiej w ogóle sie nie odzywaj

0

ja mam tylko takie pytanie: ile czasu zajmie taka pixelizacja obrazku o rozmiarach 800x600 ??

0

Dokonałem pomiarów i dla obrazka 800 x 600 sytuacja przedstawia się tak:
SetMosaic (1) ; // ok. 130 milisekund
SetMosaic (9) ; // ok. 60 milisekund
i im wieksza wartość tym czas na wykonanie operacji jest mniejszy ale nie schodzi ponizej 40 milisekund
Pewnie nie jest to jakas rewelacja... nie wie ktoś jak sprawdzić ile zajmuje taka operacja w photoshopie ? Oczywiscie nie chce porownywac osiagow mojego programu z ps, ale w przyszlosci zamierzam przepisac to wszystko do asm'a i chcialbym wiedziec jaka predkosc powinienem osiagnac zeby w ogóle warto bylo mowic o przydatnosci mojego programu ;]

aha no i zapomnialem dodac ze mam Athlona XP 2800+ (ok. 2,2 ghz) 1 GB DDR

jak ktos chce to moze sobie potestowac predkos programu na swoim kompie :) http://jagi.lcs.net.pl/test.zip // 1,2 MB gdyz w zasobach jest bitmapa 800 x 600

0

Wszystko OK tylko mam wielką prośbe, jak pobrałeś wartości RGB z pixela bitmapy ???
Chodzi mi konkretnie o środowisko Borland C++ 6.0.

0

jagi: Ten kod normalnie az sie prosi zeby w nim mmx'a wykorzystac :) Sproboj zoptymalizowac to, chetnie bym zobaczyl wyniki.

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