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; } }
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++; }
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); }
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); }
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); }
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"); */ }
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; }