implement ML model conversion, deploy models, and fix card detection noise
This commit is contained in:
parent
ff1561a704
commit
a084777e64
12 changed files with 51 additions and 47 deletions
BIN
public/models/suit_model/group1-shard1of3.bin
Normal file
BIN
public/models/suit_model/group1-shard1of3.bin
Normal file
Binary file not shown.
BIN
public/models/suit_model/group1-shard2of3.bin
Normal file
BIN
public/models/suit_model/group1-shard2of3.bin
Normal file
Binary file not shown.
BIN
public/models/suit_model/group1-shard3of3.bin
Normal file
BIN
public/models/suit_model/group1-shard3of3.bin
Normal file
Binary file not shown.
1
public/models/suit_model/model.json
Normal file
1
public/models/suit_model/model.json
Normal file
File diff suppressed because one or more lines are too long
BIN
public/models/value_model/group1-shard1of3.bin
Normal file
BIN
public/models/value_model/group1-shard1of3.bin
Normal file
Binary file not shown.
BIN
public/models/value_model/group1-shard2of3.bin
Normal file
BIN
public/models/value_model/group1-shard2of3.bin
Normal file
Binary file not shown.
BIN
public/models/value_model/group1-shard3of3.bin
Normal file
BIN
public/models/value_model/group1-shard3of3.bin
Normal file
Binary file not shown.
1
public/models/value_model/model.json
Normal file
1
public/models/value_model/model.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -18,15 +18,6 @@ const App = () => {
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<GameStateProvider>
|
||||
<AppContent />
|
||||
</GameStateProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const AppContent = () => {
|
||||
const { gameState } = useGameStateContext();
|
||||
|
||||
|
|
|
|||
|
|
@ -96,39 +96,45 @@ const Detection: React.FC<DetectionProps> = ({ videoRef, canvasRef, onCardsDetec
|
|||
|
||||
|
||||
// Enhanced card region detection specialized for Jass cards
|
||||
const findCardRegions = (imageData: ImageData, width: number, height: number): {x: number, y: number, width: number, height: number}[] => {
|
||||
const regions = [];
|
||||
const step = 12; // Adjusted step for better detection
|
||||
|
||||
// Look for card-colored regions: typically white/gray cards with identifiable suit symbols
|
||||
for (let y = 0; y < height; y += step) {
|
||||
for (let x = 0; x < width; x += step) {
|
||||
const i = (y * width + x) * 4;
|
||||
const r = imageData.data[i];
|
||||
const g = imageData.data[i + 1];
|
||||
const b = imageData.data[i + 2];
|
||||
const brightness = (r + g + b) / 3;
|
||||
|
||||
// Card background brightness range (light cards)
|
||||
if (brightness > 180 && brightness < 250) {
|
||||
const region = getCardRegionWithShapeAnalysis(imageData, width, height, x, y, step);
|
||||
if (region && region.width > 30 && region.height > 40) {
|
||||
// Check that this is a proper rectangular card area by testing aspect ratio
|
||||
const widthDiff = region.width;
|
||||
const heightDiff = region.height;
|
||||
const aspectRatio = widthDiff / heightDiff;
|
||||
|
||||
// Typical playing card aspect ratio (roughly 0.7 to 1.3)
|
||||
if (aspectRatio > 0.7 && aspectRatio < 1.3) {
|
||||
regions.push(region);
|
||||
const findCardRegions = (imageData: ImageData, width: number, height: number): {x: number, y: number, width: number, height: number}[] => {
|
||||
const regions = [];
|
||||
const step = 24; // Increased step to reduce noise and overlapping detections
|
||||
|
||||
for (let y = 0; y < height; y += step) {
|
||||
for (let x = 0; x < width; x += step) {
|
||||
const i = (y * width + x) * 4;
|
||||
const r = imageData.data[i];
|
||||
const g = imageData.data[i + 1];
|
||||
const b = imageData.data[i + 2];
|
||||
const brightness = (r + g + b) / 3;
|
||||
|
||||
if (brightness > 200 && brightness < 255) {
|
||||
const region = getCardRegionWithShapeAnalysis(imageData, width, height, x, y, step);
|
||||
if (region && region.width > 60 && region.height > 80) {
|
||||
const aspectRatio = region.width / region.height;
|
||||
if (aspectRatio > 0.6 && aspectRatio < 1.4) {
|
||||
regions.push(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return regions;
|
||||
};
|
||||
|
||||
// Remove overlapping regions to avoid "dozens of nonsense cards"
|
||||
const uniqueRegions = [];
|
||||
regions.sort((a, b) => (a.width * a.height) - (b.width * b.height));
|
||||
|
||||
for (const region of regions) {
|
||||
const isOverlapping = uniqueRegions.some(u =>
|
||||
Math.abs(u.x - region.x) < 30 && Math.abs(u.y - region.y) < 30
|
||||
);
|
||||
if (!isOverlapping) {
|
||||
uniqueRegions.push(region);
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueRegions;
|
||||
};
|
||||
|
||||
// Improved card region extraction with shape analysis for more accurate detection
|
||||
const getCardRegionWithShapeAnalysis = (imageData: ImageData, width: number, height: number, x: number, y: number, step: number): {x: number, y: number, width: number, height: number} | null => {
|
||||
|
|
|
|||
|
|
@ -77,14 +77,19 @@ const ResultsScreen: React.FC = () => {
|
|||
|
||||
<div className="cards-summary">
|
||||
<h3>Detected Cards</h3>
|
||||
<div className="cards-grid">
|
||||
{gameState.detectedCards.map(card => (
|
||||
<div key={card.id} className="card-preview">
|
||||
<div className="card-suit">♠</div>
|
||||
<div className="card-value">{card.value || '?'}pts</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="cards-grid">
|
||||
{gameState.detectedCards.map(card => (
|
||||
<div key={card.id} className="card-preview">
|
||||
<div className="card-suit">
|
||||
{card.suit === 'Schellen' && '🔔'}
|
||||
{card.suit === 'Schilten' && '🛡️'}
|
||||
{card.suit === 'Eicheln' && '🌰'}
|
||||
{card.suit === 'Rosen' && '🌹'}
|
||||
</div>
|
||||
<div className="card-value">{card.value || '?'}pts</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class CardModelService {
|
|||
private readonly VALUE_MODEL_PATH = '/models/value_model/model.json';
|
||||
|
||||
private readonly SUIT_LABELS = ['Schellen', 'Schilten', 'Eicheln', 'Rosen'];
|
||||
private readonly VALUE_LABELS = ['6', '7', '8', '9', '10', '11', '12', '13'];
|
||||
private readonly VALUE_LABELS = ['6', '7', '8', '9', '10', '11', '12', '13', '14'];
|
||||
|
||||
async init(): Promise<void> {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue