0
0

ファミコン互換機からパッキパキのピクセル抽出

Last updated at Posted at 2023-12-06

ファミコン互換機の眠い映像から、くっきりした画面を取得

Capture.png

キャプボ(カメラ)から映像を取得してCanvasのImageDataを加工します

AVerMedia.js
import {View} from './js/View.js'
 
class Pixelater extends View{
	constructor(from,to){
		super('Pixelater')
		this.delta = [10,0]//カーソルキーで微調整
		this.source = new AVerMedia(from,{loaded:e=>{
			console.log(e)
			this.in		= new Canvas(this.source.size,{willReadFrequently:true})
			this.out	= new Canvas(to,{willReadFrequently:true}).pixelate()
			this.add(this.source,this.out).update()
		}})
		document.addEventListener('keyup',e=>e.preventDefault())
		document.addEventListener('keydown',e=>{
			switch(e.key){
				case 'ArrowRight'	:this.delta[0]++	;break
				case 'ArrowLeft'	:this.delta[0]--	;break
				case 'ArrowDown'	:this.delta[1]++	;break
				case 'ArrowUp'		:this.delta[1]--	;break
				default				:return
			}
			console.log(this.delta)
			e.preventDefault()
		})
	}
	update(){
		var scale = [this.in.width/this.out.width,this.in.height/this.out.height]
		var delta = this.delta.map(n=>n/10)
		var a = this.in.drawImage(this.source).getImageData()
		var b = this.out.createImageData()
		var p = 0
		for(var y=0;y<this.out.height;y++){
			for(var x=0;x<this.out.width;x++){
				var sx = x*scale[0]+delta[0]
				var sy = y*scale[1]+delta[1]
				var sp = (Math.round(sx)+Math.round(sy)*this.in.width)*4//RGBA
				for(var i=0;i<4;i++){b.data[p++]=a.data[sp++]}
			}
		}
		this.out.putImageData(b)
		requestAnimationFrame(this.update.bind(this))
	}
}

class Canvas extends View{
	constructor(size,option){
		super('CANVAS').assign(size)
		Object.assign(this,size,{size})
		this.context = this.node.getContext('2d',option)
	}
	pixelate(){
		this.context.imageSmoothingEnabled = false
		return this.style`image-rendering:pixelated`
	}
	createImageData(){return this.context.createImageData(this.width,this.height)}
	getImageData(){return this.context.getImageData(0,0,this.width,this.height)}
	putImageData(v){this.context.putImageData(v,0,0);return this}
	drawImage(v){this.context.drawImage(v.node,0,0);return this}
}

class AVerMedia extends View.Dispatcher{
	constructor(size,...a){
		super('VIDEO AVerMedia').assign({autoplay:true,controls:true}).add(...a)
		this.size = size
		navigator.mediaDevices.getUserMedia({video:size,audio:true}).then(stream=>{
			this.node.srcObject = stream
			this.node.onloadedmetadata = e=>{
				this.size = {width:this.width,height:this.height}
				this.on('loaded',this)
			}
		}).catch(e=>console.log(e.toString()))
	}
	get width(){return this.node.videoWidth}
	get height(){return this.node.videoHeight}
}

document.body.append(
	new Pixelater(
		{width:1280,height:720},//240x3 = 720p
		{width:270,height:240}//8BIT COMPACT HDMI - VRAMイメージ
	).node
)

入力キャプチャボード:Live Gamer 4K(GC573)
https://www.avermedia.co.jp/product-detail/GC573
ファミコンHDMI出力:8BIT COMPACT HDMI
https://www.columbuscircle.co.jp/products/?id=1528173155-049425
カセット:キングオブキングス(ナムコ)
https://www.amazon.co.jp/dp/B000068H3C

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0