예제 #1
0
void GImage::blit(int x, int y, GImage* pSource)
{
	int sx = 0;
	int sy = 0;
	int sw = pSource->width();
	int sh = pSource->height();
	if(x < 0)
	{
		sx -= x;
		sw += x;
		x = 0;
	}
	if(x + sw > (int)m_width)
		sw = (int)m_width - x;
	if(y < 0)
	{
		sy -= y;
		sh += y;
		y = 0;
	}
	if(y + sh > (int)m_height)
		sh = (int)m_height - y;
	int dst = y * m_width + x;
	int src = sy * pSource->m_width + sx;
	int xx, a;
	unsigned int pix, pixOld;
	for( ; sh > 0; sh--)
	{
		for(xx = 0; xx < sw; xx++)
		{
			pix = pSource->m_pPixels[src + xx];
			a = gAlpha(pix);
			pixOld = m_pPixels[dst + xx];
			m_pPixels[dst + xx] = gARGB(std::max(a, (int)gAlpha(pixOld)),
							(a * gRed(pix) + (256 - a) * gRed(pixOld)) >> 8,
							(a * gGreen(pix) + (256 - a) * gGreen(pixOld)) >> 8,
							(a * gBlue(pix) + (256 - a) * gBlue(pixOld)) >> 8);
		}
		dst += m_width;
		src += pSource->m_width;
	}
}
예제 #2
0
void G2DRegionGraph::setMaskPixel(int x, int y, unsigned int c, size_t nRegion)
{
	GAssert(x >= 0 && x < (int)m_pRegionMask->width() && y >= 0 && y < (int)m_pRegionMask->height()); // out of range
	GAssert(m_pRegionMask->pixel(x, y) == 0xffffffff); // This pixel is already set
	m_pRegionMask->setPixel(x, y, (unsigned int)nRegion);
	struct GRegion* pRegion = m_regions[nRegion];
	pRegion->m_nSumRed += gRed(c);
	pRegion->m_nSumGreen += gGreen(c);
	pRegion->m_nSumBlue += gBlue(c);
	pRegion->m_nPixels++;
}
예제 #3
0
GSubImageFinder::GSubImageFinder(GImage* pHaystack)
{
	m_nHaystackWidth = GBits::boundingPowerOfTwo(pHaystack->width());
	m_nHaystackHeight = GBits::boundingPowerOfTwo(pHaystack->height());
	m_nHaystackX = (m_nHaystackWidth - pHaystack->width()) / 2;
	m_nHaystackY = (m_nHaystackHeight - pHaystack->height()) / 2;
	int nSize = m_nHaystackWidth * m_nHaystackHeight;
	m_pHaystackRed = new struct ComplexNumber[9 * nSize];
	m_pHaystackGreen = &m_pHaystackRed[nSize];
	m_pHaystackBlue = &m_pHaystackRed[2 * nSize];
	m_pNeedleRed = &m_pHaystackRed[3 * nSize];
	m_pNeedleGreen = &m_pHaystackRed[4 * nSize];
	m_pNeedleBlue = &m_pHaystackRed[5 * nSize];
	m_pCorRed = &m_pHaystackRed[6 * nSize];
	m_pCorGreen = &m_pHaystackRed[7 * nSize];
	m_pCorBlue = &m_pHaystackRed[8 * nSize];
	int x, y, xx, yy;
	unsigned int c;
	int pos = 0;
	for(y = 0; y < m_nHaystackHeight; y++)
	{
		yy = y - m_nHaystackY;
		for(x = 0; x < m_nHaystackWidth; x++)
		{
			xx = x - m_nHaystackX;
			if(xx >= 0 && xx < (int)pHaystack->width() && yy >= 0 && yy < (int)pHaystack->height())
			{
				c = pHaystack->pixel(xx, yy);
				m_pHaystackRed[pos].real = gRed(c) - 128;
				m_pHaystackRed[pos].imag = 0;
				m_pHaystackGreen[pos].real = gGreen(c) - 128;
				m_pHaystackGreen[pos].imag = 0;
				m_pHaystackBlue[pos].real = gBlue(c) - 128;
				m_pHaystackBlue[pos].imag = 0;
			}
			else
			{
				m_pHaystackRed[pos].real = 0;
				m_pHaystackRed[pos].imag = 0;
				m_pHaystackGreen[pos].real = 0;
				m_pHaystackGreen[pos].imag = 0;
				m_pHaystackBlue[pos].real = 0;
				m_pHaystackBlue[pos].imag = 0;
			}
			pos++;
		}
	}
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pHaystackRed, true);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pHaystackGreen, true);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pHaystackBlue, true);
}
예제 #4
0
void colorPicker::paintEvent(QPaintEvent *){
  QColor color1,color2;
  
  color1=color2=color;
  color1.setRed(0);
  color2.setRed(255);
  QPalette pRed;
  QLinearGradient gRed(0,0,bRed->width(),0);
  gRed.setColorAt( 0, color1 );
  gRed.setColorAt( 1, color2 );
  pRed.setBrush(QPalette::Window,  QBrush (gRed) );
  pRed.setBrush(QPalette::Button,  QBrush (gRed) );
  bRed->setPalette(pRed);

  color1=color2=color;
  color1.setGreen(0);
  color2.setGreen(255);
  QPalette pGreen;
  QLinearGradient gGreen(0,0,bGreen->width(),0);
  gGreen.setColorAt( 0, color1 );
  gGreen.setColorAt( 1, color2 );
  pGreen.setBrush(QPalette::Window,  QBrush (gGreen) );
  pGreen.setBrush(QPalette::Button,  QBrush (gGreen) );
  bGreen->setPalette(pGreen);

  color1=color2=color;
  color1.setBlue(0);
  color2.setBlue(255);
  QPalette pBlue;
  QLinearGradient gBlue(0,0,bBlue->width(),0);
  gBlue.setColorAt( 0, color1 );
  gBlue.setColorAt( 1, color2 );
  pBlue.setBrush(QPalette::Window,  QBrush (gBlue) );
  pBlue.setBrush(QPalette::Button,  QBrush (gBlue) );
  bBlue->setPalette(pBlue);
}
예제 #5
0
void writePng(GImage* pImage, FILE* pFile, bool bIncludeAlphaChannel)
{
	// Set the jump value (This has something to do with enabling the error handler)
	GPNGWriter writer;
	if(setjmp(png_jmpbuf(writer.m_pWriteStruct)))
		throw Ex("Failed to set the jump value");

	// Init the IO
	png_init_io(writer.m_pWriteStruct, pFile);
	png_set_compression_level(writer.m_pWriteStruct, Z_BEST_COMPRESSION);

	// Write image stats and settings
	unsigned long width = pImage->m_width;
	unsigned long height = pImage->m_height;
	png_set_IHDR(writer.m_pWriteStruct, writer.m_pInfoStruct,
		width, height, 8,
		bIncludeAlphaChannel ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
		PNG_INTERLACE_NONE,	PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	png_write_info(writer.m_pWriteStruct, writer.m_pInfoStruct);
	png_set_packing(writer.m_pWriteStruct);

	// Write the image data
	unsigned long channels = bIncludeAlphaChannel ? 4 : 3;
	unsigned long rowbytes = width * channels;
	unsigned char* pRow = new unsigned char[rowbytes];
	unsigned int* pPix = pImage->m_pPixels;
	if(channels == 4)
	{
		for(unsigned int i = 0; i < height; i++)
		{
			unsigned char* pBytes = pRow;
			for(unsigned int j = 0; j < width; j++)
			{
				*(pBytes++) = gRed(*pPix);
				*(pBytes++) = gGreen(*pPix);
				*(pBytes++) = gBlue(*pPix);
				*(pBytes++) = gAlpha(*pPix);
				pPix++;
			}
			png_write_row(writer.m_pWriteStruct, pRow);
		}
	}
	else if(channels == 3)
	{
		for(unsigned int i = 0; i < height; i++)
		{
			unsigned char* pBytes = pRow;
			for(unsigned int j = 0; j < width; j++)
			{
				*(pBytes++) = gRed(*pPix);
				*(pBytes++) = gGreen(*pPix);
				*(pBytes++) = gBlue(*pPix);
			}
			png_write_row(writer.m_pWriteStruct, pRow);
		}
	}
	else
	{
		delete[] pRow;
		throw Ex("Unsupported number of channels");
	}
	delete[] pRow;
	png_write_end(writer.m_pWriteStruct, writer.m_pInfoStruct);
}
예제 #6
0
void GSubImageFinder::findSubImage(int* pOutX, int* pOutY, GImage* pNeedle, GRect* pNeedleRect, GRect* pHaystackRect)
{
	// Copy into the array of complex numbers
	GAssert(GBits::isPowerOfTwo(pNeedleRect->w) && GBits::isPowerOfTwo(pNeedleRect->h)); // Expected a power of 2
	int x, y;
	int pos = 0;
	unsigned int c;
	for(y = 0; y < pNeedleRect->h; y++)
	{
		for(x = 0; x < pNeedleRect->w; x++)
		{
			c = pNeedle->pixel(pNeedleRect->x + x, pNeedleRect->y + y);
			m_pNeedleRed[pos].real = gRed(c) - 128;
			m_pNeedleRed[pos].imag = 0;
			m_pNeedleGreen[pos].real = gGreen(c) - 128;
			m_pNeedleGreen[pos].imag = 0;
			m_pNeedleBlue[pos].real = gBlue(c) - 128;
			m_pNeedleBlue[pos].imag = 0;
			pos++;
		}
	}

	// Convert to the Fourier domain
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleRed, true);
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleGreen, true);
	GFourier::fft2d(pNeedleRect->w, pNeedleRect->h, m_pNeedleBlue, true);

	// Multiply m_pHaystack with the complex conjugate of m_pNeedle
	double r, i, mag;
	int xx, yy;
	pos = 0;
	for(y = 0; y < m_nHaystackHeight; y++)
	{
		yy = (y * pNeedleRect->h / m_nHaystackHeight) * pNeedleRect->w;
		for(x = 0; x < m_nHaystackWidth; x++)
		{
			xx = x * pNeedleRect->w / m_nHaystackWidth;
			r = m_pNeedleRed[yy + xx].real * m_pHaystackRed[pos].real + m_pNeedleRed[yy + xx].imag * m_pHaystackRed[pos].imag;
			i = m_pNeedleRed[yy + xx].real * m_pHaystackRed[pos].imag - m_pNeedleRed[yy + xx].imag * m_pHaystackRed[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorRed[pos].real = r / mag;
			m_pCorRed[pos].imag = i / mag;
			r = m_pNeedleGreen[yy + xx].real * m_pHaystackGreen[pos].real + m_pNeedleGreen[yy + xx].imag * m_pHaystackGreen[pos].imag;
			i = m_pNeedleGreen[yy + xx].real * m_pHaystackGreen[pos].imag - m_pNeedleGreen[yy + xx].imag * m_pHaystackGreen[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorGreen[pos].real = r / mag;
			m_pCorGreen[pos].imag = i / mag;
			r = m_pNeedleBlue[yy + xx].real * m_pHaystackBlue[pos].real + m_pNeedleBlue[yy + xx].imag * m_pHaystackBlue[pos].imag;
			i = m_pNeedleBlue[yy + xx].real * m_pHaystackBlue[pos].imag - m_pNeedleBlue[yy + xx].imag * m_pHaystackBlue[pos].real;
			mag = sqrt(r * r + i * i);
			m_pCorBlue[pos].real = r / mag;
			m_pCorBlue[pos].imag = i / mag;
			pos++;
		}
	}

	// Convert to the Spatial domain
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorRed, false);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorGreen, false);
	GFourier::fft2d(m_nHaystackWidth, m_nHaystackHeight, m_pCorBlue, false);

	// Find the max
	*pOutX = 0;
	*pOutY = 0;
	double d;
	double dBest = -1e200;
	for(y = 0; y < pHaystackRect->h; y++)
	{
		yy = m_nHaystackY + pHaystackRect->y + y;
		if(yy < 0 || yy >= m_nHaystackHeight) // todo: precompute range instead
			continue;
		yy *= m_nHaystackWidth;
		for(x = 0; x < pHaystackRect->w; x++)
		{
			xx = m_nHaystackX + pHaystackRect->x + x;
			if(xx < 0 || xx >= m_nHaystackWidth) // todo: precompute range instead
				continue;
			xx += yy;
			d = m_pCorRed[xx].real * m_pCorGreen[xx].real * m_pCorBlue[xx].real;
			if(d > dBest)
			{
				dBest = d;
				*pOutX = pHaystackRect->x + x;
				*pOutY = pHaystackRect->y + y;
			}
		}
	}
/*
	// Save correlation image
	GImage corr;
	corr.setSize(m_nHaystackWidth, m_nHaystackHeight);
	pos = 0;
	for(y = 0; y < m_nHaystackHeight; y++)
	{
		for(x = 0; x < m_nHaystackWidth; x++)
		{
			d = m_pCorRed[pos].real * m_pCorGreen[pos].real * m_pCorBlue[pos].real;
			corr.setPixel(x, y, gFromGray(MAX((int)0, (int)(d * 255 * 256 / dBest))));
			pos++;
		}
	}
	corr.savePng("correlat.png");
*/
}
예제 #7
0
void GSubImageFinder2::findSubImage(int* pOutX, int* pOutY, GImage* pNeedle, GRect* pNeedleRect)
{
	// Fill a vector of candidate offsets with every possible offset
	vector<GSIFStats*> cands;
	cands.reserve((m_pHaystack->height() - pNeedleRect->h) * (m_pHaystack->width() - pNeedleRect->w));
	VectorOfPointersHolder<GSIFStats> hCands(cands);
	for(unsigned int y = 0; y + pNeedleRect->h <= m_pHaystack->height(); y++)
	{
		for(unsigned int x = 0; x + pNeedleRect->w <= m_pHaystack->width(); x++)
		{
			GSIFStats* pStats = new GSIFStats();
			cands.push_back(pStats);
			pStats->m_x = x;
			pStats->m_y = y;
			pStats->m_lastPassIter = 0;
			pStats->m_sse = 0;
		}
	}

	// Measure pixel differences until we can narrow the candidate set down to just one
	GSIFStatsComparer comparer;
	size_t ranges[2];
	ranges[0] = pNeedleRect->w;
	ranges[1] = pNeedleRect->h;
	GCoordVectorIterator cvi(2, ranges); // This chooses which pixel to try next
	for(unsigned int iters = 0; true; iters++)
	{
		// Do another pixel (penalize each candidate for any difference in that pixel)
		size_t best = INVALID_INDEX;
		size_t* pCoords = cvi.current();
		GAssert(pCoords[0] < (size_t)pNeedleRect->w && pCoords[1] < (size_t)pNeedleRect->h);
		unsigned int n = pNeedle->pixel((int)pCoords[0], (int)pCoords[1]);
		for(vector<GSIFStats*>::iterator it = cands.begin(); it != cands.end(); it++)
		{
			GSIFStats* pStats = *it;
			size_t* pCoords = cvi.current();
			unsigned int h = m_pHaystack->pixel((int)pStats->m_x + (int)pCoords[0], (int)pStats->m_y + (int)pCoords[1]);
			int dif;
			dif = gRed(h) - gRed(n);
			pStats->m_sse += (dif * dif);
			dif = gGreen(h) - gGreen(n);
			pStats->m_sse += (dif * dif);
			dif = gBlue(h) - gBlue(n);
			pStats->m_sse += (dif * dif);
			if(pStats->m_sse < best)
			{
				best = pStats->m_sse;
				*pOutX = pStats->m_x;
				*pOutY = pStats->m_y;
			}
		}

		// Divide into the best and worst halves
		vector<GSIFStats*>::iterator median = cands.begin() + (cands.size() / 2);
		std::nth_element(cands.begin(), median, cands.end(), comparer);

		// Ensure that the best half will survive for a while longer
		for(vector<GSIFStats*>::iterator it = cands.begin(); it != median; it++)
		{
			GSIFStats* pStats = *it;
			pStats->m_lastPassIter = iters;
		}

		// Kill off candidates that have been in the worst half for too long
		for(size_t i = median - cands.begin(); i < cands.size(); i++)
		{
			if(iters - cands[i]->m_lastPassIter >= 32)
			{
				size_t last = cands.size() - 1;
				delete(cands[i]);
				std::swap(cands[i], cands[last]);
				cands.erase(cands.begin() + last);
				i--;
			}
		}

		// Pick the next pixel (using a well-distributed sampling technique)
		if(!cvi.advanceSampling() || cands.size() == 1)
			break;
	}

	// Return the results
	vector<GSIFStats*>::iterator itBest = std::min_element(cands.begin(), cands.end(), comparer);
	*pOutX = (*itBest)->m_x;
	*pOutY = (*itBest)->m_y;
}