QImage KisPixelSelection::maskImage(const QRect & rc) const { // If part of a KisAdjustmentLayer, there may be no parent device. QImage img; QRect bounds; if (m_d->parentPaintDevice) { bounds = m_d->parentPaintDevice->exactBounds(); bounds = bounds.intersect(rc); img = QImage(bounds.width(), bounds.height(), QImage::Format_RGB32); } else { bounds = rc; img = QImage(bounds.width(), bounds.height(), QImage::Format_RGB32); } KisHLineConstIteratorPixel it = createHLineConstIterator(bounds.x(), bounds.y(), bounds.width()); for (int y2 = bounds.y(); y2 < bounds.height() - bounds.y(); ++y2) { int x2 = 0; while (!it.isDone()) { quint8 s = MAX_SELECTED - *(it.rawData()); qint32 c = qRgb(s, s, s); img.setPixel(x2, y2, c); ++x2; ++it; } it.nextRow(); // XXX: Why wasn't this line here? Used to be // present in 1.6. } return img; }
void KisPixelSelection::intersectSelection(KisPixelSelectionSP selection) { QRect r = selection->selectedRect().united(selectedRect()); KisHLineIteratorPixel dst = createHLineIterator(r.x(), r.y(), r.width()); KisHLineConstIteratorPixel src = selection->createHLineConstIterator(r.x(), r.y(), r.width()); for (int i = 0; i < r.height(); ++i) { while (!src.isDone()) { if (*dst.rawData() == MAX_SELECTED && *src.rawData() == MAX_SELECTED) *dst.rawData() = MAX_SELECTED; else *dst.rawData() = MIN_SELECTED; ++src; ++dst; } dst.nextRow(); src.nextRow(); } }
void KisDuplicateOp::paintAt(const KisPaintInformation& info) { if (!painter()) return; if (!m_duplicateStartIsSet) { m_duplicateStartIsSet = true; m_duplicateStart = info.pos(); } bool heal = settings->healing(); if (!source()) return; KisBrushSP brush = m_brush; if (!brush) return; if (! brush->canPaintFor(info)) return; double scale = KisPaintOp::scaleForPressure(info.pressure()); QPointF hotSpot = brush->hotSpot(scale, scale); QPointF pt = info.pos() - hotSpot; // Split the coordinates into integer plus fractional parts. The integer // is where the dab will be positioned and the fractional part determines // the sub-pixel positioning. qint32 x; double xFraction; qint32 y; double yFraction; splitCoordinate(pt.x(), &x, &xFraction); splitCoordinate(pt.y(), &y, &yFraction); xFraction = yFraction = 0.0; QPointF srcPointF = pt - settings->offset(); QPoint srcPoint = QPoint(x - static_cast<qint32>(settings->offset().x()), y - static_cast<qint32>(settings->offset().y())); qint32 sw = brush->maskWidth(scale, 0.0); qint32 sh = brush->maskHeight(scale, 0.0); if (srcPoint.x() < 0) srcPoint.setX(0); if (srcPoint.y() < 0) srcPoint.setY(0); if (!(m_srcdev && !(*m_srcdev->colorSpace() == *source()->colorSpace()))) { m_srcdev = new KisPaintDevice(source()->colorSpace()); } Q_CHECK_PTR(m_srcdev); // Perspective correction ? KisPainter copyPainter(m_srcdev); KisImageSP image = settings->m_image; if (settings->perspectiveCorrection() && image && image->perspectiveGrid()->countSubGrids() == 1) { Matrix3qreal startM = Matrix3qreal::Identity(); Matrix3qreal endM = Matrix3qreal::Identity(); // First look for the grid corresponding to the start point KisSubPerspectiveGrid* subGridStart = *image->perspectiveGrid()->begin(); QRect r = QRect(0, 0, image->width(), image->height()); #if 1 if (subGridStart) { startM = KisPerspectiveMath::computeMatrixTransfoFromPerspective(r, *subGridStart->topLeft(), *subGridStart->topRight(), *subGridStart->bottomLeft(), *subGridStart->bottomRight()); } #endif #if 1 // Second look for the grid corresponding to the end point KisSubPerspectiveGrid* subGridEnd = *image->perspectiveGrid()->begin(); if (subGridEnd) { endM = KisPerspectiveMath::computeMatrixTransfoToPerspective(*subGridEnd->topLeft(), *subGridEnd->topRight(), *subGridEnd->bottomLeft(), *subGridEnd->bottomRight(), r); } #endif // Compute the translation in the perspective transformation space: QPointF positionStartPaintingT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart)); QPointF duplicateStartPositionT = KisPerspectiveMath::matProd(endM, QPointF(m_duplicateStart) - QPointF(settings->offset())); QPointF translat = duplicateStartPositionT - positionStartPaintingT; KisRectIteratorPixel dstIt = m_srcdev->createRectIterator(0, 0, sw, sh); KisRandomSubAccessorPixel srcAcc = source()->createRandomSubAccessor(); //Action while (!dstIt.isDone()) { if (dstIt.isSelected()) { QPointF p = KisPerspectiveMath::matProd(startM, KisPerspectiveMath::matProd(endM, QPointF(dstIt.x() + x, dstIt.y() + y)) + translat); srcAcc.moveTo(p); srcAcc.sampledOldRawData(dstIt.rawData()); } ++dstIt; } } else { // Or, copy the source data on the temporary device: copyPainter.setCompositeOp(COMPOSITE_COPY); copyPainter.bitBlt(0, 0, source(), srcPoint.x(), srcPoint.y(), sw, sh); copyPainter.end(); } // heal ? if (heal) { quint16 dataDevice[4]; quint16 dataSrcDev[4]; double* matrix = new double[ 3 * sw * sh ]; // First divide const KoColorSpace* deviceCs = source()->colorSpace(); KisHLineConstIteratorPixel deviceIt = source()->createHLineConstIterator(x, y, sw); KisHLineIteratorPixel srcDevIt = m_srcdev->createHLineIterator(0, 0, sw); double* matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; !srcDevIt.isDone(); i++) { deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1); deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1); // Division for (int k = 0; k < 3; k++) { matrixIt[k] = dataDevice[k] / (double)qMax((int)dataSrcDev [k], 1); } ++deviceIt; ++srcDevIt; matrixIt += 3; } deviceIt.nextRow(); srcDevIt.nextRow(); } // Minimize energy { int iter = 0; double err; double* solution = new double [ 3 * sw * sh ]; do { err = minimizeEnergy(&matrix[0], &solution[0], sw, sh); memcpy(&matrix[0], &solution[0], sw * sh * 3 * sizeof(double)); iter++; } while (err < 0.00001 && iter < 100); delete [] solution; } // Finaly multiply deviceIt = source()->createHLineIterator(x, y, sw); srcDevIt = m_srcdev->createHLineIterator(0, 0, sw); matrixIt = &matrix[0]; for (int j = 0; j < sh; j++) { for (int i = 0; !srcDevIt.isDone(); i++) { deviceCs->toLabA16(deviceIt.rawData(), (quint8*)dataDevice, 1); deviceCs->toLabA16(srcDevIt.rawData(), (quint8*)dataSrcDev, 1); // Multiplication for (int k = 0; k < 3; k++) { dataSrcDev[k] = (int)CLAMP(matrixIt[k] * qMax((int) dataSrcDev[k], 1), 0, 65535); } deviceCs->fromLabA16((quint8*)dataSrcDev, srcDevIt.rawData(), 1); ++deviceIt; ++srcDevIt; matrixIt += 3; } deviceIt.nextRow(); srcDevIt.nextRow(); } delete [] matrix; } KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(m_srcdev->colorSpace()); fixedDab->setRect(QRect(0, 0, sw, sh)); fixedDab->initialize(); m_srcdev->readBytes(fixedDab->data(), fixedDab->bounds()); brush->mask(fixedDab, scale, scale, 0.0, info, xFraction, yFraction); m_srcdev->writeBytes(fixedDab->data(), fixedDab->bounds()); QRect dabRect = QRect(0, 0, brush->maskWidth(scale, 0.0), brush->maskHeight(scale, 0.0)); QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height()); if (painter()->bounds().isValid()) { dstRect &= painter()->bounds(); } if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; qint32 sx = dstRect.x() - x; qint32 sy = dstRect.y() - y; sw = dstRect.width(); sh = dstRect.height(); painter()->bitBlt(dstRect.x(), dstRect.y(), m_srcdev, sx, sy, sw, sh); }
lInterestPoints HarrisPointDetector::computeInterestPoints(KisPaintDeviceSP device, const QRect& rect) // lHarrisPoints computeHarrisPoints(KisPaintDeviceSP device, QRect rect) { dbgPlugins << "Compute Harris points on the rect :" << rect; Q_ASSERT(device->colorSpace()->id() == "GRAYA"); lInterestPoints points; // Compute the derivatives KisEightFloatColorSpace* floatCs = new KisEightFloatColorSpace(); KisPaintDeviceSP infoDevice = new KisPaintDevice(floatCs, "infoDevice"); float g_var = DERIVATION_SIGMA * DERIVATION_SIGMA ; float sqrt2pi = sqrt(2 * M_PI); float beta0 = 1 / (sqrt2pi * DERIVATION_SIGMA); float beta1 = beta0 * exp(-1 / (2 * g_var)); float beta2 = beta0 * exp(-4 / (2 * g_var)); float alpha1 = beta1 / g_var; float alpha2 = 2 * beta2 / g_var; { KisHLineConstIteratorPixel hitDevice = device->createHLineConstIterator(rect.left(), rect.top() + 2, rect.width() - 4); KisHLineIteratorPixel hitinfoDevice = infoDevice-> createHLineIterator(rect.left() + 2, 2, rect.width()); quint8 pixelvalue[5]; dbgPlugins << " Compute the derivatives"; dbgPlugins << " horizontal derivatives"; /* Horizontal computation of derivatives */ for (int y = rect.top() + 2; y < rect.bottom() - 2; y++) { pixelvalue[LEFTLEFT] = *hitDevice.rawData(); ++hitDevice; pixelvalue[LEFT] = *hitDevice.rawData(); ++hitDevice; pixelvalue[CENTER] = *hitDevice.rawData(); ++hitDevice; pixelvalue[RIGHT] = *hitDevice.rawData(); ++hitDevice; while (!hitDevice.isDone()) { pixelvalue[RIGHTRIGHT] = *hitDevice.rawData(); float* infoValues = reinterpret_cast<float*>(hitinfoDevice.rawData()); infoValues[INFO_HDIFF] = alpha1 * (pixelvalue[LEFT] - pixelvalue[RIGHT]) + alpha2 * (pixelvalue[LEFTLEFT] - pixelvalue[RIGHTRIGHT]); infoValues[INFO_HADD] = beta0 * (pixelvalue[CENTER]) + beta1 * (pixelvalue[LEFT] + pixelvalue[RIGHT]) + beta2 * (pixelvalue[LEFTLEFT] + pixelvalue[RIGHTRIGHT]); infoValues[INFO_INTENSITY] = pixelvalue[CENTER]; // dbgPlugins << hitDevice.x() <<"" << hitDevice.y() <<"" << infoValues[INFO_HDIFF] <<"" << infoValues[INFO_HADD] <<"" << (int)pixelvalue[CENTER] <<"" << infoValues[INFO_INTENSITY]; memmove(pixelvalue, pixelvalue + 1, 4*sizeof(quint8)); ++hitDevice; ++hitinfoDevice; } hitDevice.nextRow(); hitinfoDevice.nextRow(); } } KisTransaction a("", infoDevice); { KisVLineConstIteratorPixel vitinfoDeviceRead = infoDevice-> createVLineConstIterator(rect.left() + 4, rect.top(), rect.height()); KisVLineIteratorPixel vitinfoDevice = infoDevice-> createVLineIterator(rect.left() + 4, rect.top() + 2, rect.height() - 2); float hdiffValue[5]; float haddValue[5]; dbgPlugins << " vertical derivatives"; /* Vertical computation of derivatives */ for (int x = rect.left() + 4; x < rect.right() - 4; x++) { const float* infoValue = reinterpret_cast<const float*>(vitinfoDeviceRead.oldRawData()); hdiffValue[TOPTOP] = infoValue[INFO_HDIFF]; haddValue[TOPTOP] = infoValue[INFO_HADD]; ++vitinfoDeviceRead; infoValue = reinterpret_cast<const float*>(vitinfoDeviceRead.oldRawData()); hdiffValue[TOP] = infoValue[INFO_HDIFF]; haddValue[TOP] = infoValue[INFO_HADD]; ++vitinfoDeviceRead; infoValue = reinterpret_cast<const float*>(vitinfoDeviceRead.oldRawData()); hdiffValue[CENTER] = infoValue[INFO_HDIFF]; haddValue[CENTER] = infoValue[INFO_HADD]; ++vitinfoDeviceRead; infoValue = reinterpret_cast<const float*>(vitinfoDeviceRead.oldRawData()); hdiffValue[RIGHT] = infoValue[INFO_HDIFF]; haddValue[RIGHT] = infoValue[INFO_HADD]; ++vitinfoDeviceRead; while (!vitinfoDevice.isDone()) { infoValue = reinterpret_cast<const float*>(vitinfoDeviceRead.oldRawData()); hdiffValue[RIGHTRIGHT] = infoValue[INFO_HDIFF]; haddValue[RIGHTRIGHT] = infoValue[INFO_HADD]; float c_grdy = beta0 * hdiffValue[ CENTER ] + beta1 * (hdiffValue[ TOP ] + hdiffValue[ BOTTOM ]) + beta2 * (hdiffValue[ TOPTOP ] + hdiffValue[ BOTTOMBOTTOM ]); float c_grdx = alpha1 * (haddValue[ TOP ] - haddValue[ BOTTOM ]) + alpha2 * (haddValue[ TOPTOP ] - haddValue[ BOTTOMBOTTOM ]); float* infoValueDst = reinterpret_cast<float*>(vitinfoDevice.rawData()); infoValueDst[ INFO_XX ] = c_grdx * c_grdx; infoValueDst[ INFO_YY ] = c_grdy * c_grdy; infoValueDst[ INFO_X ] = c_grdx; infoValueDst[ INFO_Y ] = c_grdy; infoValueDst[ INFO_XY ] = c_grdx * c_grdy; memmove(hdiffValue, hdiffValue + 1, 4 * sizeof(float)); memmove(haddValue , haddValue + 1 , 4 * sizeof(float)); ++vitinfoDeviceRead; ++vitinfoDevice; } vitinfoDeviceRead.nextCol(); vitinfoDevice.nextCol(); } } // Apply a blur // Apply a blur KisTransaction("", infoDevice); #if 1 { KisHLineConstIteratorPixel hitDevice = infoDevice->createHLineConstIterator(rect.left(), rect.top() + 2, rect.width() - 4); KisHLineIteratorPixel hitinfoDevice = infoDevice-> createHLineIterator(rect.left() + 2, rect.top() + 2, rect.width() - 4); float pixelvalue[6][6]; dbgPlugins << " Compute the blur"; dbgPlugins << " horizontal blur"; /* Horizontal computation of derivatives */ for (int y = rect.top() + 2; y < rect.bottom() - 2; y++) { memcpy(pixelvalue[LEFTLEFT], hitDevice.rawData(), 6*sizeof(float)); ++hitDevice; memcpy(pixelvalue[LEFT], hitDevice.rawData(), 6*sizeof(float)); ++hitDevice; memcpy(pixelvalue[CENTER], hitDevice.rawData(), 6*sizeof(float)); ++hitDevice; memcpy(pixelvalue[RIGHT], hitDevice.rawData(), 6*sizeof(float)); ++hitDevice; while (!hitDevice.isDone()) { memcpy(pixelvalue[RIGHTRIGHT], hitDevice.rawData(), 6*sizeof(float)); float* infoValues = reinterpret_cast<float*>(hitinfoDevice.rawData()); for (int i = 0; i < 5; i++) { infoValues[i] = beta0 * pixelvalue[CENTER][i] + beta1 * (pixelvalue[LEFT][i] + pixelvalue[RIGHT][i]) + beta2 * (pixelvalue[LEFTLEFT][i] + pixelvalue[RIGHTRIGHT][i]); // infoValues[i] =2 * pixelvalue[CENTER][i] + ( pixelvalue[LEFT][i] + pixelvalue[RIGHT][i] ); } // memmove(pixelvalue, pixelvalue + 1, 4*sizeof(float[6])); for (int i = 0; i < 5; i++) { memcpy(pixelvalue[i], pixelvalue[i+1], 6*sizeof(float)); } ++hitDevice; ++hitinfoDevice; } hitDevice.nextRow(); hitinfoDevice.nextRow(); } } KisTransaction b("", infoDevice); { KisVLineConstIteratorPixel vitinfoDeviceRead = infoDevice-> createVLineConstIterator(rect.left() + 4, rect.top(), rect.height()); KisVLineIteratorPixel vitinfoDevice = infoDevice-> createVLineIterator(rect.left() + 4, rect.top() + 2, rect.height() - 4); float infoValue[6][6]; dbgPlugins << " vertical blur"; /* Vertical computation of derivatives */ for (int x = rect.left() + 4; x < rect.right() - 4; x++) { memcpy(infoValue[TOPTOP], vitinfoDeviceRead.oldRawData(), 6*sizeof(float)); ++vitinfoDeviceRead; memcpy(infoValue[TOP], vitinfoDeviceRead.oldRawData(), 6*sizeof(float)); ++vitinfoDeviceRead; memcpy(infoValue[CENTER], vitinfoDeviceRead.oldRawData(), 6*sizeof(float)); ++vitinfoDeviceRead; memcpy(infoValue[BOTTOM], vitinfoDeviceRead.oldRawData(), 6*sizeof(float)); ++vitinfoDeviceRead; while (!vitinfoDevice.isDone()) { memcpy(infoValue[BOTTOMBOTTOM], vitinfoDeviceRead.oldRawData(), 6*sizeof(float)); float* dst = reinterpret_cast<float*>(vitinfoDevice.rawData()); for (int i = 0; i < 5; i++) { dst[i] = beta0 * infoValue[CENTER][i] + beta1 * (infoValue[BOTTOM][i] + infoValue[TOP][i]) + beta2 * (infoValue[TOPTOP][i] + infoValue[BOTTOMBOTTOM][i]); // dst[i] = (2*infoValue[CENTER][i] + ( infoValue[BOTTOM][i] + infoValue[TOP][i] )) / 16; } // memmove(infoValue, infoValue + 1, 4*sizeof(float[6])); for (int i = 0; i < 5; i++) { memcpy(infoValue[i], infoValue[i+1], 6*sizeof(float)); } ++vitinfoDeviceRead; ++vitinfoDevice; } vitinfoDeviceRead.nextCol(); vitinfoDevice.nextCol(); } } #endif #if 0 KisTransaction("", infoDevice); dbgPlugins << " Blur"; { // Compute the blur mask KisAutobrushShape* kas = new KisAutobrushCircleShape(5, 5, 2, 2); QImage mask; kas->createBrush(&mask); KisKernelSP kernel = KisKernel::fromQImage(mask); // Apply the convolution to xxDevice KisConvolutionPainter infoDevicePainter(infoDevice); infoDevicePainter.beginTransaction("bouuh"); infoDevicePainter.applyMatrix(kernel, 2, 2, rect.width() - 4, rect.height() - 4, BORDER_REPEAT); delete kas; } #endif dbgPlugins << " compute curvatures"; // Compute the curvatures { KisRectIteratorPixel vitinfoDeviceRect = infoDevice->createRectIterator(2, 0, rect.width() - 2, rect.height() - 2); for (;!vitinfoDeviceRect.isDone(); ++vitinfoDeviceRect) { float* infoValue = reinterpret_cast<float*>(vitinfoDeviceRect.rawData()); float det = infoValue[INFO_XX] * infoValue[INFO_YY] - infoValue[INFO_XY] * infoValue[INFO_XY]; float trace = infoValue[INFO_XX] + infoValue[INFO_YY]; float temp = sqrt(trace * trace - 4 * det); infoValue[ INFO_HIGH ] = 0.5 * (trace + temp); infoValue[ INFO_LOW ] = 0.5 * (trace - temp); if (infoValue[ INFO_HIGH ] < infoValue[ INFO_LOW ]) { float a = infoValue[ INFO_HIGH ]; infoValue[ INFO_HIGH ] = infoValue[ INFO_LOW ]; infoValue[ INFO_LOW ] = a; } // dbgPlugins << vitinfoDeviceRect.x() <<"" << vitinfoDeviceRect.y() <<"" << infoValue[INFO_XX] <<"" << infoValue[INFO_YY] <<"" << infoValue[INFO_XY] <<"" << infoValue[INFO_HIGH] <<"" << infoValue[INFO_LOW] <<"" << trace <<"" << temp <<"" << det; } } HarrisPoints zones(5, 5, rect.width(), rect.height(), FEATURES_QUANTITY); // Detect Harris Points { int margin = 8; KisHLineIterator hitinfoDevice = infoDevice-> createHLineIterator(margin, margin, rect.width() - 2 * margin); for (int y = margin + rect.top(); y < rect.bottom() - margin; y++) { for (int x = margin + rect.left(); x < rect.right() - margin; x++, ++hitinfoDevice) { float* infoValue = reinterpret_cast<float*>(hitinfoDevice.rawData()); float low = infoValue[ INFO_LOW ]; // dbgPlugins << low; if (low > THRESHOLD_LAMBDA) { KisRectIteratorPixel vitinfoDeviceRect = infoDevice->createRectIterator(x - 1, y - 1, 3, 3); bool greater = true; for (;!vitinfoDeviceRect.isDone(); ++vitinfoDeviceRect) { if (reinterpret_cast<float*>(vitinfoDeviceRect.rawData())[ INFO_LOW ] > low) { greater = false; break; } } if (greater) { // dbgPlugins <<"new point"; HarrisPoint* hp = new HarrisPoint(x, y, infoValue[INFO_INTENSITY], infoValue[INFO_HIGH], infoValue[INFO_LOW], device); #if 0 points.push_back(hp); #endif #if 0 if (points.empty()) { points.push_back(hp); } else { if (points.size() >= FEATURES_QUANTITY && hp->low() > static_cast<HarrisPoint*>(points.back())->low()) { // remove last element, the totalNumber stay equal to FEATURES_QUANTITY points.pop_back(); } if (points.size() != FEATURES_QUANTITY) { lInterestPoints::iterator it; if (hp->low() < static_cast<HarrisPoint*>(points.back())->low()) { points.push_back(hp); } else { // insert the new corner at his right place bool inserted = false; for (it = points.begin(); it != points.end(); it++) { if (hp->low() >= static_cast<HarrisPoint*>(*it)->low()) { // dbgPlugins <<"insert point"; points.insert(it, hp); inserted = true; break; } } if (!inserted) delete hp; } } else { // hp wasn't added to the list, remove it delete hp; } } #endif #if 1 zones.instertPoint(hp); #endif } } } hitinfoDevice.nextRow(); } } points = zones.points(); dbgPlugins << "Harris detector has found :" << points.size() << " harris points"; delete floatCs; return points; }