Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package com.kik.scan
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.OvalShape
import android.os.Debug
import android.util.Log
import androidx.core.content.ContextCompat
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.getcode.codes.kikcode.LuminancePlane
import com.kik.kikx.kikcodes.ScanQuality
import com.kik.kikx.kikcodes.implementation.KikCodeScannerImpl
Expand Down Expand Up @@ -36,9 +36,18 @@ class KikCodeScanTest {
/**
* The detector locates a code by its centre ellipse, so the badge well must be filled — in the
* app that is the round logo drawable. An empty well is simply not scannable.
*
* Use the *real* artwork, not a plain white oval. The logo knocks its glyph out of the disc
* with the even-odd rule, and the glyph's round dot is itself an ellipse the detector can
* latch onto; a substituted oval has no dot and quietly hides that whole class of bug.
*/
private val renderer = KikCodeContentRendererImpl().apply {
badge = ShapeDrawable(OvalShape()).apply { paint.color = Color.WHITE }
badge = requireNotNull(
ContextCompat.getDrawable(
InstrumentationRegistry.getInstrumentation().context,
com.kik.kikx.test.R.drawable.ic_logo_round_white,
)
)
}
private val scanner = KikCodeScannerImpl()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="62dp"
android:height="62dp"
android:viewportWidth="62"
android:viewportHeight="62">
<path
android:pathData="M61.665,30.832C61.665,47.861 47.861,61.665 30.832,61.665C13.804,61.665 0,47.861 0,30.832C0,13.804 13.804,-0 30.832,-0C47.861,-0 61.665,13.804 61.665,30.832ZM24.843,15L24.811,15C22.154,15 20,17.154 20,19.811C20,22.469 22.154,24.623 24.811,24.623L24.811,24.623L34.434,24.623L34.434,24.623L37.642,24.623L39.245,24.623L39.246,24.623C41.903,24.623 44.057,22.469 44.057,19.812C44.057,17.154 41.903,15 39.246,15L39.245,15L37.642,15L34.434,15L34.434,15L24.843,15ZM34.434,27.188L36.038,27.188L36.038,27.188C38.695,27.188 40.849,29.342 40.849,32C40.849,34.657 38.695,36.811 36.038,36.811L36.038,36.811L34.434,36.811L24.858,36.811L24.811,36.811C22.154,36.811 20,34.657 20,32C20,29.343 22.154,27.188 24.811,27.188L24.811,27.188L24.811,27.188L34.434,27.188ZM29.623,44.189C29.623,41.531 27.469,39.377 24.811,39.377C22.154,39.377 20,41.531 20,44.189C20,46.846 22.154,49 24.811,49C27.469,49 29.623,46.846 29.623,44.189Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>
27 changes: 9 additions & 18 deletions vendor/kik/scanner/src/main/cpp/scan/scanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,23 +417,6 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
Mat whitish;
Mat blackish;

// --- START OF EDIT ---
// we switch to an inverted scheme (dark is high, light is low) if the
// center ellipse is dark, but we don't want to compute the extra threshold everytime
// so we only do this when needed.
//
// Using adaptive thresholding is more robust to lighting changes than a global threshold.
// It calculates a threshold for smaller regions, making it less susceptible to shadows or glare.
// A block size of 11 or higher is a good starting point and must be an odd number.
// The constant 'C' (here, 5) is subtracted from the mean, which helps in finding features.

// For finding dark features on a light background.
adaptiveThreshold(greyscale, blackish, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 21, 5);

// For finding light features on a dark background.
adaptiveThreshold(greyscale, whitish, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 21, 5);
// --- END OF EDIT ---

// we switch to an inverted scheme (dark is high, light is low) if the
// center ellipse is dark, but we don't want to compute the extra threshold everytime
// so we only do this when necessary
Expand Down Expand Up @@ -728,7 +711,15 @@ bool detectKikCode(Mat &greyscale, Mat *out_progress, uint32_t device_quality, u
float dist = sqrt(pow(center1.x - center2.x, 2)
+ pow(center1.y - center2.y, 2));

if (dist < 50 && 2 * potential_ellipses[i].size.area() > potential_ellipses[j].size.area()) {
float area1 = potential_ellipses[i].size.area();
float area2 = potential_ellipses[j].size.area();

// Only prune true near-duplicates -- the same physical circle fitted twice from the
// inner and outer edge of its stroke, which are comparable in area. A nearby ellipse
// that is much smaller is a *different* feature nested inside this one (e.g. the dot
// knocked out of the centre badge's glyph), and dropping the enclosing candidate in
// its favour loses the only ellipse that can yield finder points.
if (dist < 50 && 2 * area1 > area2 && 2 * area2 > area1) {
allowed = false;
break;
}
Expand Down
Loading