private void PrepareOsdArea(uint[] dataIn, uint[] dataOut, uint[] dataDebugNoLChD, int width, int height) { //DebugPrepareOsdArea(dataIn, dataOut, width, height); //return; // Split into fields only in the region where IOTA-VTI could be, Then threat as two separate images, and for each of them do: // 1) Gaussian blur (small) BitmapFilter.LOW_PASS_FILTER_MATRIX // 2) Sharpen BitmapFilter.SHARPEN_MATRIX // 3) Binarize - get Average, all below change to 0, all above change to Max (256) // 4) De-noise BitmapFilter.DENOISE_MATRIX if (m_UseNativePreProcessing) { TangraCore.PrepareImageForOCR(dataIn, dataOut, width, height); } else { uint median = dataIn.Median(); for (int i = 0; i < dataIn.Length; i++) { int darkCorrectedValue = (int)dataIn[i] - (int)median; if (darkCorrectedValue < 0) { darkCorrectedValue = 0; } dataIn[i] = (uint)darkCorrectedValue; } uint[] blurResult = BitmapFilter.GaussianBlur(dataIn, 8, width, height); uint average = 128; uint[] sharpenResult = BitmapFilter.Sharpen(blurResult, 8, width, height, out average); // Binerize and Inverse for (int i = 0; i < sharpenResult.Length; i++) { sharpenResult[i] = sharpenResult[i] > average ? (uint)0 : (uint)255; } uint[] denoised = BitmapFilter.Denoise(sharpenResult, 8, width, height, out average, false); for (int i = 0; i < denoised.Length; i++) { dataOut[i] = denoised[i] < 127 ? (uint)0 : (uint)255; } Array.Copy(dataOut, dataDebugNoLChD, dataOut.Length); LargeChunkDenoiser.Process(false, dataOut, width, height); } }
private bool LocateTimestampPosition(uint[] data, int frameWidth, int frameHeight) { uint[] preProcessedPixels = new uint[data.Length]; Array.Copy(data, preProcessedPixels, data.Length); // Process the image uint median = preProcessedPixels.Median(); for (int i = 0; i < preProcessedPixels.Length; i++) { int darkCorrectedValue = (int)preProcessedPixels[i] - (int)median; if (darkCorrectedValue < 0) { darkCorrectedValue = 0; } preProcessedPixels[i] = (uint)darkCorrectedValue; } if (median > 250) { //InitiazliationError = "The background is too bright."; return(false); } uint[] blurResult = BitmapFilter.GaussianBlur(preProcessedPixels, 8, frameWidth, frameHeight); uint average = 128; uint[] sharpenResult = BitmapFilter.Sharpen(blurResult, 8, frameWidth, frameHeight, out average); // Binerize and Inverse for (int i = 0; i < sharpenResult.Length; i++) { sharpenResult[i] = sharpenResult[i] > average ? (uint)0 : (uint)255; } uint[] denoised = BitmapFilter.Denoise(sharpenResult, 8, frameWidth, frameHeight, out average, false); for (int i = 0; i < denoised.Length; i++) { preProcessedPixels[i] = denoised[i] < 127 ? (uint)0 : (uint)255; } int bestBottomPosition = -1; int bestTopPosition = -1; LocateTopAndBottomLineOfTimestamp( preProcessedPixels, frameWidth, frameHeight / 2 + 1, frameHeight, out bestTopPosition, out bestBottomPosition); if (bestBottomPosition - bestTopPosition < 10 || bestBottomPosition - bestTopPosition > 60 || bestTopPosition < 0 || bestBottomPosition > frameHeight) { return(false); } int fromLine = bestTopPosition - 1; int toLine = bestBottomPosition + 3; if (toLine > frameHeight) { toLine = frameHeight - 2; } if ((toLine - fromLine) % 2 == 1) { if (fromLine % 2 == 1) { fromLine--; } else { toLine++; } } #region We need to make sure that the two fields have the same top and bottom lines // Create temporary arrays so the top/bottom position per field can be further refined int fieldAreaHeight = (toLine - fromLine) / 2; int fieldAreaWidth = frameWidth; uint[] oddFieldPixelsPreProcessed = new uint[frameWidth * fieldAreaHeight]; uint[] evenFieldPixelsPreProcessed = new uint[frameWidth * fieldAreaHeight]; int[] DELTAS = new int[] { 0, -1, 1 }; int fromLineBase = fromLine; int toLineBase = toLine; bool matchFound = false; for (int deltaIdx = 0; deltaIdx < DELTAS.Length; deltaIdx++) { fromLine = fromLineBase + DELTAS[deltaIdx]; toLine = toLineBase + DELTAS[deltaIdx]; int bestBottomPositionOdd = -1; int bestTopPositionOdd = -1; int bestBottomPositionEven = -1; int bestTopPositionEven = -1; LocateTopAndBottomLineOfTimestamp( oddFieldPixelsPreProcessed, fieldAreaWidth, 1, fieldAreaHeight - 1, out bestTopPositionOdd, out bestBottomPositionOdd); LocateTopAndBottomLineOfTimestamp( evenFieldPixelsPreProcessed, fieldAreaWidth, 1, fieldAreaHeight - 1, out bestTopPositionEven, out bestBottomPositionEven); if (bestBottomPositionOdd == bestBottomPositionEven && bestTopPositionOdd == bestTopPositionEven) { matchFound = true; fromLine = fromLineBase; toLine = toLineBase; break; } } #endregion if (matchFound) { UpdateVtiOsdPositions(fromLine, toLine); } return(matchFound); }
private void DebugPrepareOsdArea(uint[] dataIn, uint[] dataOut, int width, int height) { // NOTE: Because of different rounding in C++ and C# there may be a difference of "1" between pixels uint[] nativeIn = new uint[dataIn.Length]; uint[] nativeOut = new uint[dataOut.Length]; uint nativeAverage = 0; for (int i = 0; i < dataIn.Length; i++) { nativeIn[i] = dataIn[i]; } uint median = dataIn.Median(); for (int i = 0; i < dataIn.Length; i++) { int darkCorrectedValue = (int)dataIn[i] - (int)median; if (darkCorrectedValue < 0) { darkCorrectedValue = 0; } dataIn[i] = (uint)darkCorrectedValue; } TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 0, ref nativeAverage); Trace.Assert(Math.Abs(median - nativeAverage) <= 1); for (int i = 0; i < nativeOut.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - dataIn[i]) <= 1); } for (int i = 0; i < dataIn.Length; i++) { nativeIn[i] = dataIn[i]; } uint[] blurResult = BitmapFilter.GaussianBlur(dataIn, 8, width, height); TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 1, ref nativeAverage); for (int i = 0; i < nativeOut.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - blurResult[i]) <= 1); } for (int i = 0; i < blurResult.Length; i++) { nativeIn[i] = blurResult[i]; } uint average = 128; uint[] sharpenResult = BitmapFilter.Sharpen(blurResult, 8, width, height, out average); TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 2, ref nativeAverage); Trace.Assert(Math.Abs(average - nativeAverage) <= 1); for (int i = 0; i < nativeOut.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - sharpenResult[i]) <= 1); } for (int i = 0; i < sharpenResult.Length; i++) { nativeIn[i] = sharpenResult[i]; } TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 3, ref nativeAverage); // Binerize and Inverse for (int i = 0; i < sharpenResult.Length; i++) { sharpenResult[i] = sharpenResult[i] > average ? (uint)0 : (uint)255; } for (int i = 0; i < nativeOut.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - sharpenResult[i]) <= 1); } for (int i = 0; i < sharpenResult.Length; i++) { nativeIn[i] = sharpenResult[i]; } TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 4, ref nativeAverage); uint[] denoised = BitmapFilter.Denoise(sharpenResult, 8, width, height, out average, false); for (int i = 0; i < denoised.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - denoised[i]) <= 1); } for (int i = 0; i < denoised.Length; i++) { nativeIn[i] = denoised[i]; } TangraCore.PrepareImageForOCRSingleStep(nativeIn, nativeOut, width, height, 5, ref nativeAverage); for (int i = 0; i < denoised.Length; i++) { dataOut[i] = denoised[i] < 127 ? (uint)0 : (uint)255; } for (int i = 0; i < denoised.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - dataOut[i]) <= 1); } LargeChunkDenoiser.Process(false, dataOut, width, height); LargeChunkDenoiser.Process(true, nativeOut, width, height); for (int i = 0; i < dataOut.Length; i++) { Trace.Assert(Math.Abs(nativeOut[i] - dataOut[i]) <= 1); } for (int i = 0; i < nativeOut.Length; i++) { dataOut[i] = nativeOut[i]; } }
private bool LocateTimestampPosition(uint[] data) { uint[] preProcessedPixels = new uint[data.Length]; Array.Copy(data, preProcessedPixels, data.Length); // Process the image uint median = preProcessedPixels.Median(); for (int i = 0; i < preProcessedPixels.Length; i++) { int darkCorrectedValue = (int)preProcessedPixels[i] - (int)median; if (darkCorrectedValue < 0) { darkCorrectedValue = 0; } preProcessedPixels[i] = (uint)darkCorrectedValue; } if (median > 250) { InitiazliationError = "The background is too bright."; return(false); } uint[] blurResult = BitmapFilter.GaussianBlur(preProcessedPixels, 8, m_InitializationData.FrameWidth, m_InitializationData.FrameHeight); uint average = 128; uint[] sharpenResult = BitmapFilter.Sharpen(blurResult, 8, m_InitializationData.FrameWidth, m_InitializationData.FrameHeight, out average); // Binerize and Inverse for (int i = 0; i < sharpenResult.Length; i++) { sharpenResult[i] = sharpenResult[i] > average ? (uint)0 : (uint)255; } uint[] denoised = BitmapFilter.Denoise(sharpenResult, 8, m_InitializationData.FrameWidth, m_InitializationData.FrameHeight, out average, false); for (int i = 0; i < denoised.Length; i++) { preProcessedPixels[i] = denoised[i] < 127 ? (uint)0 : (uint)255; } int bestBottomPosition = -1; int bestTopPosition = -1; LocateTopAndBottomLineOfTimestamp( preProcessedPixels, m_InitializationData.FrameWidth, m_InitializationData.FrameHeight / 2 + 1, m_InitializationData.FrameHeight, out bestTopPosition, out bestBottomPosition); if (bestBottomPosition - bestTopPosition < 10 || bestBottomPosition - bestTopPosition > 60) { bool tryBestTopAndLastLine = m_InitializationData.FrameHeight - bestTopPosition > 10 && m_InitializationData.FrameHeight - bestTopPosition < 60; if (tryBestTopAndLastLine) { bestBottomPosition = m_InitializationData.FrameHeight - 1; } else { if (m_ForceErrorReport) { if (m_ForceErrorReport && !m_CalibrationImages.ContainsKey("LocateTimestampPositionOrg.bmp")) { uint[] pixelsOriginal = new uint[data.Length]; Array.Copy(data, pixelsOriginal, data.Length); AddErrorImage("LocateTimestampPositionOrg.bmp", pixelsOriginal, 0, 0); uint[] pixelsPreProcessed = new uint[data.Length]; Array.Copy(preProcessedPixels, pixelsPreProcessed, data.Length); AddErrorImage("LocateTimestampPositionProcessed.bmp", pixelsPreProcessed, 0, 0); } } InitiazliationError = "Cannot locate the OSD timestamp on the frame."; return(false); } } m_FromLine = bestTopPosition - 10; m_ToLine = bestBottomPosition + 10; if (m_ToLine > m_InitializationData.FrameHeight) { m_ToLine = m_InitializationData.FrameHeight - 2; } if ((m_ToLine - m_FromLine) % 2 == 1) { if (m_FromLine % 2 == 1) { m_FromLine--; } else { m_ToLine++; } } #region We need to make sure that the two fields have the same top and bottom lines // Create temporary arrays so the top/bottom position per field can be further refined m_FieldAreaHeight = (m_ToLine - m_FromLine) / 2; m_FieldAreaWidth = m_InitializationData.FrameWidth; m_OddFieldPixels = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; m_EvenFieldPixels = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; m_OddFieldPixelsPreProcessed = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; m_EvenFieldPixelsPreProcessed = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; m_OddFieldPixelsDebugNoLChD = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; m_EvenFieldPixelsDebugNoLChD = new uint[m_InitializationData.FrameWidth * m_FieldAreaHeight]; int[] DELTAS = new int[] { 0, -1, 1 }; int fromLineBase = m_FromLine; int toLineBase = m_ToLine; PrepareOsdVideoFields(data); for (int deltaIdx = 0; deltaIdx < DELTAS.Length; deltaIdx++) { m_FromLine = fromLineBase + DELTAS[deltaIdx]; m_ToLine = toLineBase + DELTAS[deltaIdx]; int bestBottomPositionOdd = -1; int bestTopPositionOdd = -1; int bestBottomPositionEven = -1; int bestTopPositionEven = -1; LocateTopAndBottomLineOfTimestamp( m_OddFieldPixelsPreProcessed, m_FieldAreaWidth, 1, m_FieldAreaHeight - 1, out bestTopPositionOdd, out bestBottomPositionOdd); LocateTopAndBottomLineOfTimestamp( m_EvenFieldPixelsPreProcessed, m_FieldAreaWidth, 1, m_FieldAreaHeight - 1, out bestTopPositionEven, out bestBottomPositionEven); if (bestBottomPositionOdd == bestBottomPositionEven && bestTopPositionOdd == bestTopPositionEven) { m_FromLine = fromLineBase; m_ToLine = toLineBase; break; } } #endregion m_TVSafeModeGuess = m_ToLine + (m_ToLine - m_FromLine) / 2 < m_InitializationData.FrameHeight; return(true); }