標籤:

心理學如何用MATLAB生成適合屏幕的刺激

作為MATLAB初學者,你猜我為什麼要班門弄斧不自量力寫教程?QAQ

這裡面可能有代碼優化、敘述不當等問題,望大家指正以及包涵。感謝!

文中圖片由本人自己製作繪畫或拍攝,部分代碼由網路、課本、他人代碼基礎上修改,僅作學習交流用。

文章轉載請註明出處。

事情是這樣的,這學期MATLAB期末考試有一題,用PTB編一整個實驗程序。程序框架在這裡不做贅述。實驗對刺激材料在屏幕上的呈現有嚴格要求,要求是黑底白字,在屏幕上不止要求比例,還要較為精確的絕對尺寸。具體尺寸要求如下:

我們知道,現在市面上的顯示器大小不一,相對解析度、絕對解析度(dpi)都不一樣,要想生成這樣滿足要求的刺激並不容易(我相信有大神很不屑於這個,但對我來說真的很難啊有木有)。作為一個初學者的教程,我們從最基礎的東西講起吧。

================廢話鋪墊篇================

在我講教程之前,先介紹幾個概念。

解析度,指的是在點陣圖和點陣中指這個點陣圖點陣可被識別的程度。分為三種(其實後兩種可以合併):

1、 相對解析度(Resolution),也就是我們常說的像素,電子點陣圖顯示器、點陣圖圖片,都由像素組成。對心理學編程來說,在MATLAB里用的都是正方形像素。像素與像素構成一個點陣,根據上面的顏色、灰度等變化構成一個圖像。通常來說,像素越多越細膩,圖像越清晰。相對解析度只代表了這個點陣像素的個數,與絕對長度沒有直接關係。也就是說,一個1920*1080的屏幕,可以是一台5英寸手機屏幕,也可以是一台50寸的液晶電視,還可能是200寸的投影屏。

2、 絕對解析度(dpi) 這裡用比較常用的dpi來講。Dpi,dots perinch,每英寸的點陣個數。這個就可以把點陣個數與絕對長度單位聯繫起來了——插一句,網上外行經常把信息技術里的「像素」「解析度」「dpi」等概念混淆,就像把「內存」和「存儲空間」混淆一樣,都習慣了——同時,dpi在描述圖片、文印、屏幕點陣過程中,數字越大則代表越清晰越細膩。

3、 PPI 如今的屏幕已經不止是「點」了,而是一個個有顏色、亮度、透明度的像素。因此在屏幕上我們通常稱dpi是PPI(pixels per inch),每英寸的像素個數。嘛對於一個學心理的來說這個怎麼叫應該無所謂吧(別打我)。

絕對長度、像素解析度、PPI只要知道其中的兩個,就可以求出第三個,對應關係是

長度(英寸)=像素個數/PPI

1 inch=25.4 mm

比如,1920*1080,180PPI的屏幕,其

寬度是1920 / 180 = 10.67 inch = 27.09cm;

高度是1080 / 180 = 6 inch = 15.24 cm ;

其屏幕尺寸(對角線)是 ( 10.67^2 + 6^2 )^0.5 =12.24 inch

一個十二寸的1080P屏幕。

在大多數的心理學試驗中,特別是行為實驗,只要求被試可以無壓力識別刺激即可,對刺激本身的清晰度要求並不高。同時為了減少因為實驗儀器計算壓力過大而產生的時差,因此採用夠用的低解析度的屏幕,比如1024*768,甚至有些地方只用800*600。

=====================正題篇=====================

回到這個題目(終於回歸正題),我們最先想到的,就是利用顯示器的像素和PPI來達到目的,然後調整字型大小就可以啦!

教程到此結束,謝謝觀看!

才怪嘞!還有一個問題別忽略了!

那就是

字體

(捂臉)

不同字體、粗細,都會影響切邊,從而無法達到實驗目的。

考慮上面各種因素後,MATLAB編程怎麼沒有程序呢?所以終於進入程序部分。

===================真の正題===================

代碼是個枯燥的部分,基本就是給代碼+解釋說明+運行結果。

下面的部分除了截圖外我盡量用MATLAB能夠識別的格式,讓需要的同學直接複製粘貼就能用。由於初學,我的編寫習慣不是很好,如果有優化代碼請多多指教。

第一步: 算出你的數據

之前鋪墊了很多關於解析度PPI的知識,現在就派上用場了。

本猴用的是ThinkPad X1tablet ,如果不了解的童鞋,先到村裡(中關村在線)查配置。屏幕標稱12英寸2K屏,PPI為216。

額當然你也可以自己算一下。量出來屏幕寬度正好是10英寸,PPI是216

然後就是位置計算啦,統一單位為我們熟知的厘米,那麼PPI換算成PPC(pixels per centimeter,像素每厘米)只要除以2.54就行。

216 PPI = 216 pixels / 2.54 cm = 85.03937007874016…PPC

是吧,我說沒法完全精確吧~

如果把數字外框看成矩形的話,那麼我們可以把題目中的數字換算成像素(這個數值僅適配於PPI為216的屏幕)。

這一步都還好,細心的同學就會發現幾個問題了:

如何保證數字頂在方格裡面?

兩個數字高寬比不一樣啊,怎麼辦?

沒事,我們開始一一解決。

第二步:頂格的數字素材

這段代碼修改自2017年6月30日 @juno芊 的生成素材代碼,主要修改了說明和優化了循環體。字體選用和字型大小設置都是她經過多次實踐測試後得出的。

% 終於開始用matlab寫程序了。經過我們的經驗,很多字體並不能很好押在框內。我們最後選用了Arial字體,能夠較好匹配,調整較少。%% 生成所需的數字圖片1-9% 背景的顏色是黑色% 文字的顏色是白色,字體是Arial,文字的字型大小大小為默認% 文字儘可能頂著四邊,不留縫隙,減小誤差% 數字1為特殊,不做要求% 文字在畫布的居中位置clear;clc; %日常清理mkdir image %創建一個圖片文件夾叫image。不做描述它會創建在這個m文件所在目錄for i =1:9 %循環9次,每次生成一個數字NumName(i) = num2str(i); %每次生成的文字內容即循環的序號%第1次生成圖片1,第2次生成圖片2,以此類推。但內容必須是字元figure; % 打開一個繪圖窗口set(gcf,color,Black,... units,pixels,... position,[100 100 360 540]); %讓figure背景變為黑色。其中gcf表示get current figure,指代當前窗口。%窗口大小是360*540,算好的。t_text = text(0.5,0.5,NumName(i)); %建立一個text,寫上「1」-9, set(t_text,FontName,Arial,... %設置我們精挑細選的字體Arial,居中正好 FontSize,560,... %設置文字大小560,也是算好的。 Color,[1 1 1],HorizontalAlignment, center,VerticalAlignment,middle) %設置文字顏色為白色,位置居中axis off%關閉坐標軸NewNumName = sprintf(%s%s%s,pic_,NumName(i),.jpg);%臨時新名字,用於指代文件名(帶後綴)f=getframe(gcf); %別忘了把現在的窗口「截圖」變成圖形矩陣imwrite(f.cdata,[image,NewNumName]) %寫入圖片close gcf; %關閉當前窗口,不然你屏幕上一堆窗口。end

這個程序成功運行之後,你會發現一個新的文件夾,裡面的素材基本上都頂齊了。

當然個別數字頂不齊主要怪字體。大家可以嘗試不同的字體與比例搭配,這裡就不列舉了。

第三步:拼出你的刺激畫面

又是一通計算,算出來結果如圖。不過值得一提的是,在普通情況下,MATLAB的起始像素點從屏幕左下角開始算,而在PTB里是從左上角開始算。

所以在PTB下我們需要算出兩個數字矩形的左上角的坐標。這裡算好了

左邊數字左上角(x , y)是(825 ,656),右下角是(910,784);

右邊數字左上角(x , y)是(1220,622),右下角是(1365,818)。

第四步:打出來!

在PTB里寫好實驗程序,包括主程序和每個trail,反應時記錄、被試按鍵記錄等等,這裡不做贅述。就講講刺激呈現的頁面。

假設其它程序框架已經搭好了,現在只呈現單個trail的刺激。

這段代碼在蔣老師的整個實驗程序 Singletrail Function功能代碼基礎上截取修改。主要修改了脫離主程序可以運行、屏幕圖片參數修改、加入位置和位移、插入詳細解釋說明、結束段等。

Screen(Preference,SkipSyncTests, 1); Screen(Preference, ConserveVRAM, 64); %設置屏幕,這兩句話通常寫在主函數前面的,這裡為了方便大家運行可以直接拷貝%以下是單個trail里的顯示內容w = Screen(OpenWindow,0);%打開窗口,全屏Screen(FillRect,w,0);%創建黑屏pic1name = pic_2.jpg;pic2name = pic_3.jpg;LPIC = imread([image,pic1name]); RPIC = imread([image,pic2name]); % 讀取 .jpg 圖片 lGratingIndex = Screen(MakeTexture, w, LPIC); rGratingIndex = Screen(MakeTexture, w, RPIC); %將讀取好的圖製作成圖片,用GratingIndex來指代。 %這是PTB的一種圖片顯示機制,給顯示器運算用的 GRect = Screen(Rect,lGratingIndex); GRect = Screen(Rect,rGratingIndex); % 求當前圖片的位置 Screen(DrawTexture,w,lGratingIndex, GRect, [825,656,910,784]); Screen(DrawTexture,w,rGratingIndex, GRect, [1220,622,1365,818]); %將GratingIndex畫到屏幕畫板上,GRect是圖片原始位置 %後一個是目標位置,坐標分別是上一步算好的第一個,第二個Screen(Flip,w);%出現吧,屏幕! KbWait; % 按任意鍵繼續 ShowCursor; % 顯示 Screen(CloseAll); %結束,關閉屏幕

大功告成!!

如果想要正式實驗,還要把trail變成一個功能(function),輸入參數是一個隨機好的表單,數字文件名稱被很好隨機過替換即可。這裡就不列舉了。

附加:猴子你出來!這是怎麼回事!?

剛剛的程序明明寫好了,算好了,沒問題,為啥有的朋友呈現結果是這樣的↓

有人就說了:猴子你出來!保證不打死你!為啥右下半邊被吃了?

吼吼吼那我來解釋一下吧。

我們先用下面代碼跑一遍看看:

Screen(Preference,SkipSyncTests, 1); Screen(Preference, ConserveVRAM, 64);[w, wRect] = Screen(OpenWindow,0);Screen(CloseAll);

跑完以後,PTB檢測到的屏幕解析度參數就顯示在wRect裡面了。

不看不知道,一看嚇一跳,為啥我的2K屏幕變成1234*823了?

難道是MATLAB的解析度檢測代碼出問題?

其實是因為你用了Windows 8及以上系統,裡面有個系統畫面縮放搞的鬼。

以我的win10系統為例,桌面,右鍵,顯示設置,就可以看到,畫面被放大了175%

也就是說,2160的橫向解析度只有2160/1.75=1234了。

那麼,解決方案有兩個

一個是,按照1234*823的解析度重新算PPI和像素位置。

第二個,把175%在實驗時改成100%。

兩個辦法各有利弊,反正我懶,選了後者。然後我就開啟了瞎眼模式……

(高分屏的孩子懂得)

不過最後尺寸還算令猴滿意。

=====================分割線====================

最後,感謝教我MATLAB的蔣老師,讓我在短短四個月強行進入MATLAB殿堂。感謝一起學習的同學們,在互相交流經驗中學習成長。最後,感謝您能讀到這裡。

這個程序本身可能有瑕疵,比如這樣的代碼不夠高效,程序效率低下,普通處理器可能延遲較高等,以後有機會還能努力學習優化。再次感謝您的觀看!
推薦閱讀:

Matlab如何動態呈現計算結果
用matlab求矩陣的最大特徵值怎麼求?AHP分析法中,最大特徵值有虛部嗎?是否可以求出所有特徵值找最大的?
MATLAB和物聯網連載3: Thingspeak Tutorial 2
Matlab如何實現截屏與屏幕錄製
Matlab如何從曲線圖中提取原始數據

TAG:心理學 | MATLAB |