DEV Community

王龙
王龙

Posted on

I Built an AI Tool to Reconstruct Matcha-Filtered Images—Here’s What I Learned

A heavily stylized “matcha” filter can do more than shift colors toward green. It can flatten skin tones, posterize shadows, exaggerate edges, replace texture, and destroy small details.

That creates an interesting product question:

Can generative AI turn the remaining visual structure into a natural-looking image again?

I recently built Matcha Filter Remover, a small AI tool that explores exactly that problem. This post is a practical breakdown of what worked, what did not, and the engineering decisions that mattered most.

First: reconstruction is not recovery

This was the most important product decision.

When a destructive filter overwrites pixels, those original pixels are gone. No model can reliably recover the exact source photo from information that no longer exists.

The tool therefore does AI reconstruction, not original-photo recovery.

That distinction appears throughout the product:

  • The output is described as a new AI-generated interpretation.
  • Exact identity, text, logos, hands, jewelry, and background details are not guaranteed.
  • The before/after interface keeps the filtered input visible.
  • The product never claims forensic restoration or access to hidden content.

This is not only safer wording. It also sets an honest user expectation for a probabilistic system.

The model comparison surprised me

I tested multiple image-editing models with different kinds of matcha-filtered inputs.

The first test image was a portrait with a strong yellow-green embossed effect. The second was a tiny, low-resolution café scene with severe edge enhancement and very little reliable color information.

Two models stood out:

  • Seedream 5 Pro produced cleaner color reconstruction and stronger overall photographic coherence.
  • Nano Banana Pro was useful as a fallback, especially when preserving composition, but sometimes left more of the original green cast in the image.

For this specific task, Seedream became the primary model and Nano Banana the fallback.

The key lesson was that “best image model” is too broad a question. A model can be excellent at creative editing but weak at removing a particular destructive visual style. The evaluation set has to resemble the actual user input.

I also stopped relying on an aggressive pre-classification step. In practice, matcha-filter detection produced too many uncertain or incorrect decisions. A false negative is especially frustrating because the user already knows why they uploaded the image.

The current workflow instead uses a fixed, conservative reconstruction prompt and lets the image editor handle the full scene.

Prompt design: constrain the invention

A useful prompt for this workflow needs two opposing properties:

  1. Remove the strong artificial filter.
  2. Avoid redesigning the entire image.

The prompt emphasizes:

  • natural photographic color and lighting;
  • preservation of pose, framing, subject placement, and scene structure;
  • removal of olive/yellow-green tint, embossed edges, posterization, and false texture;
  • realistic skin, fabric, objects, and background;
  • no beautification, identity substitution, or unrelated additions;
  • no claim that the result is the original photo.

This does not eliminate hallucination, but it gives the model a much narrower job than “make this look good.”

The production architecture

The app is built with:

  • Next.js 16 and React 19 for the application;
  • Cloudflare Workers for the runtime;
  • Cloudflare D1 for users, credits, jobs, and payment records;
  • Cloudflare R2 for temporary uploads and generated results;
  • Cloudflare Queues for asynchronous reconstruction jobs;
  • fal.ai for image-generation models;
  • Google OAuth for account access;
  • Stripe Checkout for one-time credit purchases.

A simplified request flow looks like this:

Browser upload
  -> authenticated API route
  -> temporary R2 object
  -> D1 job + credit reservation
  -> Cloudflare Queue
  -> primary image model
  -> output safety check
  -> temporary R2 result
  -> authenticated result page
Enter fullscreen mode Exit fullscreen mode

Uploads and results are scheduled for deletion within 24 hours. The credit balance itself does not expire.

Payments were more than adding a button

Stripe Checkout made card collection straightforward, but reliable fulfillment still required server-side work.

The live payment flow validates:

  • the Checkout Session belongs to the signed-in user;
  • the session is in live mode;
  • payment status is paid;
  • currency and amount match the selected pack;
  • the returned Stripe Price ID matches the server configuration.

Credits are granted through an idempotent ledger entry. If Stripe retries the webhook—or the success page and webhook both request fulfillment—the same Checkout Session cannot grant credits twice.

The site sells one-time packs rather than subscriptions:

  • 8 credits for $4.99
  • 20 credits for $9.99
  • 45 credits for $19.99

Purchased credits remain available until used.

Safety boundaries belong in the architecture

An image reconstruction tool can be misunderstood if its limits are vague.

The product explicitly prohibits:

  • explicit content;
  • content involving minors;
  • non-consensual imagery;
  • clothing removal or “see-through” behavior;
  • private-content reveal claims;
  • attempts to bypass safety controls.

Generated results pass an output safety check before being retained and displayed. A blocked or failed job returns the reserved reconstruction credit through an idempotent refund entry.

The UI also requires the user to confirm that they are 18+ and own the image or have permission to use it.

These decisions are not a policy-page afterthought. They affect job state, storage, credit accounting, result delivery, and copy across the entire product.

What I would do differently

1. Build the evaluation set first

I initially spent too much time tuning around individual examples. A small benchmark containing portraits, objects, indoor scenes, tiny images, text-heavy images, and multiple filter strengths would have made model selection faster.

2. Treat copy as part of system design

Phrases such as “remove,” “restore,” and “recover” can imply very different capabilities. The final product repeatedly uses “AI reconstruction” because the system generates plausible pixels rather than retrieves missing ones.

3. Test mobile checkout early

One responsive CSS rule accidentally hid all purchase buttons on mobile. Desktop tests passed; mobile end-to-end tests caught it before launch.

4. Make every credit mutation idempotent

Generation failures, safety blocks, webhook retries, and payment redirects can all repeat. A ledger with unique idempotency keys is much safer than directly incrementing and decrementing a balance in scattered code paths.

5. Keep temporary media and permanent entitlements separate

Images expire after 24 hours for privacy. Purchased credits do not expire. Mixing those concepts would create confusing product behavior and complicated data retention rules.

The result

The project is now live at matchafilterremover.online.

It is still an experiment in a narrow visual problem, and the output will not be perfect. But that constraint is exactly what made the build interesting: model quality, honest product language, privacy, safety, async processing, and payment integrity all had to work together.

If you are building a small AI image product, my biggest recommendation is simple:

Evaluate on the real failure cases, and design the product around what the model cannot know.

I would love to hear how other developers evaluate image-editing models or design reliable credit-based AI workflows.

Top comments (0)