Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #11 (permalink)  
Старый 15.08.2015, 19:23
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Paguo-86PK, вроде как запилил определение размеров указателя (кисти) и для примера нарисовал его розовым

Исходники тут.

Разумеется, писал не с нуля, поскреб по сусекам

Теперь надо этим маркером (указателем) пройти лабиринт, собирая опорные точки.
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #12 (permalink)  
Старый 15.08.2015, 22:34
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Спасибо за вклад
Сообщение от nerv_ Посмотреть сообщение
Paguo-86PK, вроде как запилил определение размеров указателя (кисти) и для примера нарисовал его розовым

Исходники тут.

Разумеется, писал не с нуля, поскреб по сусекам

Теперь надо этим маркером (указателем) пройти лабиринт, собирая опорные точки.
Спасибо
Правда, что-то слишком сложно. И мне несколько неудобно за напряг (не думал, что Вы расписывать будете код)

Просто, меня заинтересовало наличие готовых решений в этой области (как, скажем, OpenCV).

Подход с предопределением ширины кисти может быть сбойным, если в режиме реального времени с вэб-камеры эскиз лабиринта считывается с боковой стенки. Ширина кисти ближней к объективу камеры стенки лабиринта будет больше, чем дальняя, в силу законов перспективной проекции.

Сейчас я пишу (в час - по чайной ложке) скрипт (дописываю тот же залитый мной в архив), где жук оснащён радаром. Он собирает ширину и длину лучей, проходящих по пути. Двигается по наидлинейщему пути со статистически стабильной шириной. Тем самым, ширина может изменяться по мере перемещения по маршруту.
Недостаток: Крайне низкая скорость, непригодная для режима реального времени (как у Zbar).
К тому же, код пока просто выдаёт график огибающей окружения.

P.S.: По идее, чтобы задумку выдать за свою и иметь полное право на неё, я должен справиться сам.
Повторяюсь: Думал, есть готовые библиотеки (типа OpenCV).

P.P.S.: Применение: На многих форумах задумку просто осмеяли и задаваться там проблемой распознавания как-то неудобно
Так как основное применение сообществом воспринимается дегенеративным.
Ответить с цитированием
  #13 (permalink)  
Старый 15.08.2015, 22:54
без статуса
Отправить личное сообщение для Deff Посмотреть профиль Найти все сообщения от Deff
 
Регистрация: 25.05.2012
Сообщений: 8,219

Сообщение от Paguo-86PK
Так как основное применение сообществом воспринимается дегенеративным
Да нет, тут скорее желание убежать от сложнозадачи, даже поиска нужных компонентов OpenCV
Посколь имел опыт с попыткой добить нечто подобное, так что nerv_, на моих глазах совершил подвиг самонапряга, правда тут есть ещё пара тройка подобных личностей, могущих себя самоувлечь и помочь
Ответить с цитированием
  #14 (permalink)  
Старый 16.08.2015, 00:40
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Сообщение от Paguo-86PK
Спасибо
на здоровье

Сообщение от Paguo-86PK
Правда, что-то слишком сложно.
мне кажется наоборот)

Сообщение от Paguo-86PK
Подход с предопределением ширины кисти может быть сбойным
а может и не быть)

Сообщение от Paguo-86PK
если в режиме реального времени с вэб-камеры эскиз лабиринта считывается с боковой стенки. Ширина кисти ближней к объективу камеры стенки лабиринта будет больше, чем дальняя, в силу законов перспективной проекции.
я не рассматривал задачу в таком контексте. Моя трактовка более простая.
коме того размер кисти вычисляется достаточно быстро

Сообщение от Paguo-86PK
По идее, чтобы задумку выдать за свою и иметь полное право на неё, я должен справиться сам
ну, прости

---

Сообщение от Deff
Посколь имел опыт с попыткой добить нечто подобное, так что nerv_, на моих глазах совершил подвиг самонапряга, правда тут есть ещё пара тройка подобных личностей, могущих себя самоувлечь и помочь
эм... подвиг есть не спорю, только не стоит его преувеличивать. Повторюсь, я поскреб по сусекам и, посути, надергал уже готовых модулей из своих проектов. Список всех приведен тут. Из них, под данную задачу с нуля я писал только Decoder & MatrixWalker, Rectangle, из которых последние два очевидные в своей реализации (думать не надо, только пиши).

Возвращаясь к теме
Сообщение от Paguo-86PK
Правда, что-то слишком сложно.
Лично мне проще:
- взять свой ранее написанный класс/модуль и подпилить его под себя (чем заново изобретать велосипед)
- писать на es6 с использованием классов и модулей, чем использовать процедурной подход. ООП позволяет сравнительно легко управлять сложностью приложения
а если ты посмотришь в index.js, то увидишь, что, по сути, у меня есть декодер, который всем заведует. Но, т.к. приложение не дописано, сейчас в нем не очень чисто В идеале (как-то так):

import Decoder from './modules/Decoder';


let {document} = window;
let image = document.getElementById('original');
let stage = document.getElementById('stage');


let decoder = new Decoder();

decoder.onDecodeComplete = function() {
    decoder.write(stage);
};

decoder.decode(image);

куда уж проще)
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук

Последний раз редактировалось nerv_, 16.08.2015 в 00:44.
Ответить с цитированием
  #15 (permalink)  
Старый 16.08.2015, 00:54
Аватар для cyber
I am Student
Отправить личное сообщение для cyber Посмотреть профиль Найти все сообщения от cyber
 
Регистрация: 17.12.2011
Сообщений: 4,415

nerv_, на чем научился писать подобные штуки?)
__________________
Цитата:
Если ограничения и условия описываются как "коробка", то хитрость в том что бы найти именно коробку... Не думайте о чем то глобальном - найдите коробку.
Ответить с цитированием
  #16 (permalink)  
Старый 16.08.2015, 09:25
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Сообщение от nerv_ Посмотреть сообщение
на здоровье
мне кажется наоборот)
Думаю, я слишком примитивно владею программированием, поэтому и кажется, что Ваш код сложен.

Для примера, набыдлокодил здесь эмулятор+дизассемблер+ассе мблер своего процессора, где можно оценить и мой стиль, и уровень владения. (звук работает в Chrome)

По теме: Я подумал, что распознание лабиринта пересекается с OCR. По сути, в этом плане мои лабиринты очень правильные: Нет оторваных стенок, нет глухих комнат, и путь всегда один (в данной версии я в концепции не развивал проход лабиринта в двух и более маршрутах).

P.S.: Кстати, мою идею осмеяли, потому что я решил строить/читать лабиринты со скрытым смыслом.
Я взял Муна, Хангыль, принцип Пентамино и составил собственный алфавит, конвертируя слова в лабиринты. (В противовес QR-коду, который без смартфона чудовищно сложно глазами прочитать)
Гласные звуки - буквы корейского алфавита.
Согласные звуки - частично шрифт Муна и греческий алфавит.
Причём, парные глухие и звонкие согласные имеют одну фигурку.
Код:
 (Ι  Β
  │  Π
    ┌─┐
 ΚΓ┌ Ω ┐MN
  ┌  ┴  ┐
ΣC│E┤©├A│DT
  └  ┬  ┘
 RL└ Υ ┘JH
    └─┘
     V
     F)
Один лабиринт - одно слово.
Ниже - архив с подсказками и анимациями.

Для чего это надо?
Во-первых, такие лабиринты легко печатаются на 3D-принтере. Так как имеют "правильную" структуру: Нет оторваных стен и глухих комнат.
Во-вторых, при должном навыке человек может научиться читать лабиринты за час (собственная мама в роли подопытной прочитала стихи за 15 минут). Не говоря уже о машине.
В-третьих, тактильно лабиринты можно читать пальцами при должном навыке.

Ну как? И на этом форуме идею назовёте дегенератской?
Вложения:
Тип файла: zip hints.zip (229.9 Кб, 1 просмотров)

Последний раз редактировалось Paguo-86PK, 17.08.2015 в 18:36. Причина: Добавил архив
Ответить с цитированием
  #17 (permalink)  
Старый 15.05.2021, 07:36
Аватар для Paguo-86PK
Профессор
Отправить личное сообщение для Paguo-86PK Посмотреть профиль Найти все сообщения от Paguo-86PK
 
Регистрация: 16.09.2009
Сообщений: 253

Human Quick Response Labyrintic Text
Накoнец-то чуточку продвинулся в решении поставленной задачи.

Если раньше пытался решать её со стороны графики - сканированием изображения, что просаживало производительность.
То теперь реализован математический подход.
И можно видеть, чертя мышью лабиринт на чёрном поле, насколько отзывчиво производится его предварительная обработка в мерцающую фигуру.
<html>
<head>
<style>
body	{
	margin		:0px 0px 0px 0px;
	padding		:0px 0px 0px 0px;
}
</style>
<script>
var	hPprCnv;
var	hPprCtx;
var	hSrcCnv;
var	hSrcCtx;
var	hCtrCnv;
var	hCtrCtx;
var	hPrvCnv;
var	hPrvCtx;
var	hRslCnv;
var	hRslCtx;
var	vecs;
var	circle;
var	iStepFactor = 32;

// sharp
// Процедура бинарной резкости
CanvasRenderingContext2D.prototype.sharp =
function	() {
	var	imd = this.getImageData(0, 0, this.canvas.width, this.canvas.height);
	var	p = imd.data;
	var	i = p.length,
		r, g, b,
		x, y, z = 384;
	var	mask;
	while(i >= 4) {
		-- i;
		r = (p[-- i] >> 7) * 255; g = (p[-- i] >> 7) * 255; b = (p[-- i] >> 7) * 255;
		mask = z < r + g + b ? 255 : 0;
		p[i + 3] = 255, p[i + 2] = mask, p[i + 1] = mask, p[i + 0] = mask;
		if(mask)
			y = i >> 2;
	}
	x = y % this.canvas.width;
	y = (y - x) / this.canvas.width;
	this.putImageData(imd, 0, 0);
	return	{
		x	:x + 1,
		y	:y + 1
	}
}

// Процедура обнаружения границ
CanvasRenderingContext2D.prototype.findEdge =
function	() {
	var	w = this.canvas.width;
	var	j = i - w * 4 - 4;
	var	x, y, z = 384;
	var	r, g, b;
	var	k, m, r;
	var	dx, dy;
	var	minx = 1 << 30;
	var	miny = 1 << 30;
	var	maxx = 0;
	var	maxy = 0;
	var	mindy;
	var	maxdy;
	var	arr = [];
	var	corners = [];
	var	borders = [];
	var	tmp;
	var	lasta = "";
	var	lastx, lasty;
	//
	this.save();
	this.globalCompositeOperation = "difference";
	this.drawImage(this.canvas, 1, 1);
	this.restore();
	var	imd = this.getImageData(1, 1, this.canvas.width, this.canvas.height);
	var	buf = imd.data;
	var	i = imd.data.length;
	var	pixels = new Uint32Array(imd.data.buffer);
	var	j = pixels.length;
	var	fnd = -1;
	do {
		fnd = Array.prototype.indexOf.call(pixels, 0xFFFFFFFF, fnd + 1);
		if(fnd >= 0) {
			x = fnd % this.canvas.width,
			y = Math.floor(fnd / this.canvas.width);
			minx = Math.min(minx, x);
			miny = Math.min(miny, y);
			maxx = Math.min(maxx, x);
			maxy = Math.min(maxy, y);
			arr.push({
				x	:x,
				y	:y,
				a	:""
			});
		}
	} while(fnd >= 0);
	// Сортировка пикселей контура в цепочку
	for(i = 0; i < arr.length - 1; ++ i) {
		x = arr[i].x;
		y = arr[i].y;
		k = 0;
		for(j = i + 1; j < arr.length; ++ j) {
			dx = arr[j].x - x, dy = arr[j].y - y;
			r = Math.sqrt(dx * dx + dy * dy);
			if(k == 0 || m > r)
				m = r,
				k = j;
		}
		arr.splice(i + 1, 0, arr.splice(k, 1)[0]);
	}
	/*var	point = { x: arr[0].x, y: arr[0].y };
	arr.sort((a, b) => {
		var d = (a.x - point.x) ** 2 + (a.y - point.y) ** 2 - (b.x - point.x) ** 2 + (b.y - point.y) ** 2;
		point = { x: b.x, y: b.y};
		return d;
	});*/
	// Построение "маршрута" движения (векторной ориентации) линий контура
	for(i = 0; i < arr.length; ++ i) {
		var	east = 0;
		var	west = 0;
		var	south = 0;
		var	north = 0;
		for(j = 1; j <= iStepFactor; ++ j) {
			tmp = arr[j];
			dx = tmp.x - arr[0].x, dy = tmp.y - arr[0].y;
			if(Math.abs(dx) > Math.abs(dy)) {
				if(dx < 0)
					east ++;
				else
					west ++;
			} else
				if(dy < 0)
					south ++;
				else
					north ++;
		}
		var	max = Math.max(east, west, north, south);
		arr[0].a = max == east ? "E" : max == west ? "W" : max == north ? "N" : "S";
		if(lasta != arr[0].a) {
			corners.push({
				x	:arr[0].x,
				y	:arr[0].y,
				a	:lasta
			});
			if(lasta != "") {
				if(!(lasta == "E" || "W" == lasta))
					borders.push({
						x1	:lastx,
						y1	:lasty,
						x2	:arr[0].x,
						y2	:lasty
					});
				else
					borders.push({
						x1	:lastx,
						y1	:lasty,
						x2	:lastx,
						y2	:arr[0].y
					});
			}
			lastx = arr[0].x,
			lasty = arr[0].y;
		}
		lasta = arr[0].a;
		arr.push(arr.shift());
	}
	for(i = 0; i < corners.length - 1; ++ i) {
		x = corners[i].x;
		y = corners[i].y;
		for(j = i + 1; j < corners.length; ++ j) {
		}
	}
	//
	corners.push({
		x	:arr[0].x,
		y	:arr[0].y,
		a	:lasta
	});
	return {
		arr	:arr,
		corners	:corners,
		borders	:borders
	};
}

var	vecmax	= 0;
var	vecidx	= 0;
var	paths	= [{len: []}];

var	car	= {
		x	:0,
		y	:100,
		dx	:1,
		dy	:1,
		dir	:0.0,
		cdx	:0,	// Counter by dx
		cdy	:0	// Counter by dy
	};
var	pen	= {
		x	:0,
		y	:100
	};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var	lapping	= 0;
var	race	= [];
var	curdir	= "";
var	cntdir	= "";
var	waydir	= "";
var	lastdir	= "";

function  run() {
	var	colors = {
			"N"	:"red",
			"S"	:"magenta",
			"E"	:"blue",
			"W"	:"cyan"
		};
	pixels.unshift(pixels.pop());
	hRslCtx.clearRect(0, 0, hRslCnv.width, hRslCnv.height);
	hRslCtx.beginPath();
	var	x, y, nx, ny;
	for(i = 0; i < corners.length; ++ i) {
		nx = corners[i].x, ny = corners[i].y;
		if(corners[i].a == "E" ||  "W" == corners[i].a) {
			hRslCtx.lineTo(x, ny);
		} else {
			hRslCtx.lineTo(nx, y);
		}
		dx = nx - x, dy = ny - y;
		;
		x = nx, y = ny;
		if(i)
			hRslCtx.lineTo(x, y);
		else
			hRslCtx.moveTo(x, y);
	}
	hRslCtx.fillStyle = "grey brown red orange yellow green cyan blue magenta black".split(" ")[Math.floor(Math.random() * 10)];
	hRslCtx.fillStyle = "grey silver".split(" ")[Math.floor(Math.random() * 2)];
	hRslCtx.closePath();
	hRslCtx.fill();
	//hRslCtx.stroke();
	hRslCtx.beginPath();
	for(i = 0; i < borders.length; ++ i) {
		nx = borders[i].x1, ny = borders[i].y1;
		hRslCtx.moveTo(nx, ny);
		hRslCtx.lineTo(borders[i].x2, borders[i].y2);
	}
	hRslCtx.strokeStyle = "grey brown red orange yellow green cyan blue magenta black".split(" ")[Math.floor(Math.random() * 10)];
	hRslCtx.closePath();
	hRslCtx.lineWidth = 4;
	hRslCtx.stroke();
	return;
	////////////////////////////////////////////////////////////////////////////////
}

var	hqr;
var	pixels;
var	corners;
var	borders;

function main() {
	hPprCnv = document.getElementById("Paper");
	hSrcCnv = document.getElementById("Source");
	hCtrCnv = document.getElementById("Contour");
	hPrvCnv = document.getElementById("Preview");
	hRslCnv = document.getElementById("Result");
	hSrcCnv.setAttribute('crossOrigin', '');
	hPprCtx = hPprCnv.getContext("2d");
	hCtrCtx = hCtrCnv.getContext("2d");
	hSrcCtx = hSrcCnv.getContext("2d");
	hPrvCtx = hPrvCnv.getContext("2d");
	hRslCtx = hRslCnv.getContext("2d");
	hPprCtx.fillStyle = "#FF00000";
	hPprCtx.fillRect(0, 0, hPprCnv.width, hPprCnv.height);
	hSrcCtx.fillStyle = "#FF000000";
	hPrvCtx.fillStyle = "#CCCCCC";
	hSrcCtx.fillRect(0, 0, hSrcCnv.width, hSrcCnv.height);
	hPprCnv.addEventListener("mousemove",
		function(e) {
			x = e.offsetX;
			y = e.offsetY;
			if(e.buttons == 1) {
				hPprCtx.fillStyle = "white";
				hPprCtx.fillRect(x, y, 16, 16);
				hSrcCtx.drawImage(hPprCnv, 0, 0);
				localStorage.draftImage = hPprCnv.toDataURL();
				Start();
			}
		}
	);
	hPprCnv.addEventListener("mouseup",
		function(e) {
			hSrcCtx.drawImage(hPprCnv, 0, 0);
			localStorage.draftImage = hPprCnv.toDataURL();
			Start();
		}
	);
	hSrcCnv.addEventListener("mousemove",
		function(e) {
			x = e.offsetX;
			y = e.offsetY;
			if(e.buttons == 1) {
				hSrcCtx.fillStyle = "white";
				hSrcCtx.fillRect(x, y, 16, 16);
			}
		}
	);
	if(localStorage.draftImage) {
		var	im = new Image();
		im.src = localStorage.draftImage;
		im.addEventListener("load", function(e) {
				hPprCtx.drawImage(e.target, 0, 0);
			}
		);
	}
}
function loadDefault() {
	hSrcCtx.drawImage(document.getElementsByTagName("img")[0], 0, 0, hSrcCnv.width, hSrcCnv.height);
	setTimeout('Start(); hSrcCnv.style.qdisplay="none"; setInterval("run(); run(); run();", 1);', 1000);
}
function Start() {
	vecs = [hSrcCtx.sharp()];
	car.x = vecs[0].x;
	car.y = vecs[0].y;
	pen.x = car.x;
	pen.y = car.y;
	tmp = hSrcCtx.findEdge();
	pixels = tmp.arr;
	corners = tmp.corners;
	borders = tmp.borders;
	car.x = pixels[0].x;
	car.y = pixels[0].y;
	lapping = 0;
	race = [];
	waydir = "";
	curdir = "";
	cntdir = 0;
}
function Clear() {
	hSrcCtx.fillStyle="black";
	hSrcCtx.fillRect(0, 0, hSrcCnv.width, hSrcCnv.height);
	hPprCtx.fillStyle = "black";
	hPprCtx.fillRect(0, 0, hPprCnv.width, hPprCnv.height);

}
</script>
<style>
img,
canvas#Source,
canvas#Contour,
canvas#Preview	{
	display	:none;
}
</style>
</head>
<body onload='main()'>
<button onclick='hqr.Bug()' style=display:none>Step</button>
<button onclick='Clear()'>Clear</button>
<button onclick='Start()' style=display:none>Start</button><hr />
<canvas id='Paper' width='320' height='240'></canvas><canvas id='Source' width='320' height='240'></canvas>
<canvas id='Contour' width='320' height='240' style='display:none'></canvas><canvas id='Preview' width='320' height='240'></canvas>
<canvas id='Result' width='320' height='240'></canvas>
<img style=display:none title='animanu.gif' src1='https://i.imgur.com/oZBA50h.png' src='https://i.imgur.com/NDa8KXn.gif' crossorigin = '' onload='setTimeout(loadDefault, 100)' /></img>
<div style=display:none>
<pre id='log'>---</pre>
<pre id='Log'></pre>
</div>
</body>
</html>

Последний раз редактировалось Paguo-86PK, 16.05.2021 в 04:12.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
JavaScript проход лабиринта sinkalexęą Общие вопросы Javascript 1 07.12.2013 13:29