Improve image preprocessing
This commit is contained in:
		
							parent
							
								
									5f53aaec23
								
							
						
					
					
						commit
						cb203b912e
					
				@ -90,34 +90,118 @@ static double getScale(Pix *source)
 | 
				
			|||||||
  return scale;
 | 
					  return scale;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Smart pointer for Pix
 | 
				
			||||||
 | 
					class PixGuard
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  explicit PixGuard(Pix *pix = nullptr)
 | 
				
			||||||
 | 
					    : pix_(pix)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ~PixGuard()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (pix_)
 | 
				
			||||||
 | 
					      pixDestroy(&pix_);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void operator=(Pix *pix)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (!pix)
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    if (pix_)
 | 
				
			||||||
 | 
					      pixDestroy(&pix_);
 | 
				
			||||||
 | 
					    pix_ = pix;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  operator Pix *() { return pix_; }
 | 
				
			||||||
 | 
					  Pix *operator->() { return pix_; }
 | 
				
			||||||
 | 
					  Pix *&get() { return pix_; }
 | 
				
			||||||
 | 
					  Pix *take()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    auto ret = pix_;
 | 
				
			||||||
 | 
					    pix_ = nullptr;
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void trace(const QString &name) const
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    LTRACE() << qPrintable(name) << pix_;
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    if (!pix_)
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    auto fileName = name + ".png";
 | 
				
			||||||
 | 
					    fileName.replace(' ', "_");
 | 
				
			||||||
 | 
					    convertImage(*pix_).save(fileName);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					  Pix *pix_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Q_DISABLE_COPY(PixGuard);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static Pix *prepareImage(const QImage &image)
 | 
					static Pix *prepareImage(const QImage &image)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  auto pix = convertImage(image);
 | 
					  auto pix = PixGuard(convertImage(image));
 | 
				
			||||||
  SOFT_ASSERT(pix, return nullptr);
 | 
					  SOFT_ASSERT(pix, return nullptr);
 | 
				
			||||||
  LTRACE() << "Converted Pix" << pix;
 | 
					  pix.trace("Pix 1 Converted");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto gray = pixConvertRGBToGray(pix, 0.0, 0.0, 0.0);
 | 
					  {
 | 
				
			||||||
  LTRACE() << "Created gray Pix" << gray;
 | 
					    pix = pixConvertRGBToGray(pix, 0.0, 0.0, 0.0);
 | 
				
			||||||
  SOFT_ASSERT(gray, return nullptr);
 | 
					    pix.trace("Pix 2 Gray");
 | 
				
			||||||
  pixDestroy(&pix);
 | 
					 | 
				
			||||||
  LTRACE() << "Removed converted Pix";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  auto scaleSource = gray;
 | 
					 | 
				
			||||||
  auto scaled = scaleSource;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (const auto scale = getScale(scaleSource); scale > 1.0) {
 | 
					 | 
				
			||||||
    scaled = pixScale(scaleSource, scale, scale);
 | 
					 | 
				
			||||||
    LTRACE() << "Scaled Pix for OCR" << LARG(scale) << LARG(scaled);
 | 
					 | 
				
			||||||
    if (!scaled)
 | 
					 | 
				
			||||||
      scaled = scaleSource;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (scaled != scaleSource) {
 | 
					  if (const auto scale = getScale(pix); scale > 1.0) {
 | 
				
			||||||
    pixDestroy(&scaleSource);
 | 
					    pix = pixScaleGrayLI(pix, scale, scale);
 | 
				
			||||||
    LTRACE() << "Removed unscaled Pix";
 | 
					    pix.trace("Pix 3 Scaled");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return scaled;
 | 
					  l_int32 otsuSx = 5000;
 | 
				
			||||||
 | 
					  l_int32 otsuSy = 5000;
 | 
				
			||||||
 | 
					  l_int32 otsuSmoothx = 0;
 | 
				
			||||||
 | 
					  l_int32 otsuSmoothy = 0;
 | 
				
			||||||
 | 
					  l_float32 otsuScorefract = 0.1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    PixGuard otsu;
 | 
				
			||||||
 | 
					    pixOtsuAdaptiveThreshold(pix, otsuSx, otsuSy, otsuSmoothx, otsuSmoothy,
 | 
				
			||||||
 | 
					                             otsuScorefract, nullptr, &otsu.get());
 | 
				
			||||||
 | 
					    pix.trace("Pix 4 Test Color Otsu");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Get the average intensity of the border pixels,
 | 
				
			||||||
 | 
					    // with average of 0.0 being completely white and 1.0 being completely black
 | 
				
			||||||
 | 
					    // Top
 | 
				
			||||||
 | 
					    auto avg = pixAverageOnLine(otsu, 0, 0, otsu->w - 1, 0, 1);
 | 
				
			||||||
 | 
					    // Bottom
 | 
				
			||||||
 | 
					    avg += pixAverageOnLine(otsu, 0, otsu->h - 1, otsu->w - 1, otsu->h - 1, 1);
 | 
				
			||||||
 | 
					    // Left
 | 
				
			||||||
 | 
					    avg += pixAverageOnLine(otsu, 0, 0, 0, otsu->h - 1, 1);
 | 
				
			||||||
 | 
					    // Right
 | 
				
			||||||
 | 
					    avg += pixAverageOnLine(otsu, otsu->w - 1, 0, otsu->w - 1, otsu->h - 1, 1);
 | 
				
			||||||
 | 
					    avg /= 4.0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If background is dark
 | 
				
			||||||
 | 
					    l_float32 threshold = 0.5f;
 | 
				
			||||||
 | 
					    if (avg > threshold) {
 | 
				
			||||||
 | 
					      pix = pixInvert(nullptr, pix);
 | 
				
			||||||
 | 
					      pix.trace("Pix 5 Inverted");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    l_int32 usm_halfwidth = 5;
 | 
				
			||||||
 | 
					    l_float32 usm_fract = 2.5f;
 | 
				
			||||||
 | 
					    pix = pixUnsharpMaskingGray(pix, usm_halfwidth, usm_fract);
 | 
				
			||||||
 | 
					    pix.trace("Pix 6 Unshapred");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    pixOtsuAdaptiveThreshold(pix, otsuSx, otsuSy, otsuSmoothx, otsuSmoothy, 0.0,
 | 
				
			||||||
 | 
					                             nullptr, &pix.get());
 | 
				
			||||||
 | 
					    pix.trace("Pix 7 Binarized");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pix.trace("Pix 8 Result");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return pix.take();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void cleanupImage(Pix **image)
 | 
					static void cleanupImage(Pix **image)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user